From 7b398939f72a37b2a47b95b0e9dfe464af62dec8 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 9 Nov 2025 03:12:49 -0600 Subject: [PATCH] Refactor compose and deployment services: streamline cloning and execution commands, remove redundant remote functions, and enhance error handling. Update database schema to include application build server ID for better tracking of deployments. --- apps/dokploy/server/api/routers/compose.ts | 9 +- .../server/queues/deployments-queue.ts | 85 ++-- packages/server/src/db/schema/deployment.ts | 6 + packages/server/src/services/application.ts | 260 +++--------- packages/server/src/services/compose.ts | 235 ++--------- packages/server/src/services/deployment.ts | 16 +- packages/server/src/utils/builders/compose.ts | 28 +- .../server/src/utils/builders/docker-file.ts | 17 +- packages/server/src/utils/builders/heroku.ts | 13 +- packages/server/src/utils/builders/index.ts | 19 +- .../server/src/utils/builders/nixpacks.ts | 51 ++- packages/server/src/utils/builders/paketo.ts | 13 +- .../server/src/utils/builders/railpack.ts | 21 +- packages/server/src/utils/builders/static.ts | 18 +- packages/server/src/utils/cluster/upload.ts | 25 +- packages/server/src/utils/docker/collision.ts | 7 +- packages/server/src/utils/docker/domain.ts | 69 +--- .../server/src/utils/process/execAsync.ts | 6 +- .../server/src/utils/providers/bitbucket.ts | 205 +-------- packages/server/src/utils/providers/git.ts | 391 +++--------------- packages/server/src/utils/providers/gitea.ts | 235 +---------- packages/server/src/utils/providers/github.ts | 232 ++--------- packages/server/src/utils/providers/gitlab.ts | 235 +---------- packages/server/src/utils/providers/raw.ts | 31 +- 24 files changed, 386 insertions(+), 1841 deletions(-) diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index e2f25b763..026b6e8ad 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -3,13 +3,14 @@ import { addNewService, checkServiceAccess, cloneCompose, - cloneComposeRemote, createCommand, createCompose, createComposeByTemplate, createDomain, createMount, deleteMount, + execAsync, + execAsyncRemote, findComposeById, findDomainsByComposeId, findEnvironmentById, @@ -302,10 +303,12 @@ export const composeRouter = createTRPCRouter({ message: "You are not authorized to fetch this compose", }); } + + const command = await cloneCompose(compose); if (compose.serverId) { - await cloneComposeRemote(compose); + await execAsyncRemote(compose.serverId, command); } else { - await cloneCompose(compose); + await execAsync(command); } return compose.sourceType; } catch (err) { diff --git a/apps/dokploy/server/queues/deployments-queue.ts b/apps/dokploy/server/queues/deployments-queue.ts index b8dfb8cd0..a1d9d29f1 100644 --- a/apps/dokploy/server/queues/deployments-queue.ts +++ b/apps/dokploy/server/queues/deployments-queue.ts @@ -2,13 +2,9 @@ import { deployApplication, deployCompose, deployPreviewApplication, - deployRemoteApplication, - deployRemoteCompose, deployRemotePreviewApplication, rebuildApplication, rebuildCompose, - rebuildRemoteApplication, - rebuildRemoteCompose, updateApplicationStatus, updateCompose, updatePreviewDeployment, @@ -24,68 +20,35 @@ export const deploymentWorker = new Worker( if (job.data.applicationType === "application") { await updateApplicationStatus(job.data.applicationId, "running"); - if (job.data.server) { - if (job.data.type === "redeploy") { - await rebuildRemoteApplication({ - applicationId: job.data.applicationId, - titleLog: job.data.titleLog, - descriptionLog: job.data.descriptionLog, - }); - } else if (job.data.type === "deploy") { - await deployRemoteApplication({ - applicationId: job.data.applicationId, - titleLog: job.data.titleLog, - descriptionLog: job.data.descriptionLog, - }); - } - } else { - if (job.data.type === "redeploy") { - await rebuildApplication({ - applicationId: job.data.applicationId, - titleLog: job.data.titleLog, - descriptionLog: job.data.descriptionLog, - }); - } else if (job.data.type === "deploy") { - await deployApplication({ - applicationId: job.data.applicationId, - titleLog: job.data.titleLog, - descriptionLog: job.data.descriptionLog, - }); - } + if (job.data.type === "redeploy") { + await rebuildApplication({ + applicationId: job.data.applicationId, + titleLog: job.data.titleLog, + descriptionLog: job.data.descriptionLog, + }); + } else if (job.data.type === "deploy") { + await deployApplication({ + applicationId: job.data.applicationId, + titleLog: job.data.titleLog, + descriptionLog: job.data.descriptionLog, + }); } } else if (job.data.applicationType === "compose") { await updateCompose(job.data.composeId, { composeStatus: "running", }); - - if (job.data.server) { - if (job.data.type === "redeploy") { - await rebuildRemoteCompose({ - composeId: job.data.composeId, - titleLog: job.data.titleLog, - descriptionLog: job.data.descriptionLog, - }); - } else if (job.data.type === "deploy") { - await deployRemoteCompose({ - composeId: job.data.composeId, - titleLog: job.data.titleLog, - descriptionLog: job.data.descriptionLog, - }); - } - } else { - if (job.data.type === "deploy") { - await deployCompose({ - composeId: job.data.composeId, - titleLog: job.data.titleLog, - descriptionLog: job.data.descriptionLog, - }); - } else if (job.data.type === "redeploy") { - await rebuildCompose({ - composeId: job.data.composeId, - titleLog: job.data.titleLog, - descriptionLog: job.data.descriptionLog, - }); - } + if (job.data.type === "deploy") { + await deployCompose({ + composeId: job.data.composeId, + titleLog: job.data.titleLog, + descriptionLog: job.data.descriptionLog, + }); + } else if (job.data.type === "redeploy") { + await rebuildCompose({ + composeId: job.data.composeId, + titleLog: job.data.titleLog, + descriptionLog: job.data.descriptionLog, + }); } } else if (job.data.applicationType === "application-preview") { await updatePreviewDeployment(job.data.previewDeploymentId, { diff --git a/packages/server/src/db/schema/deployment.ts b/packages/server/src/db/schema/deployment.ts index d6b0ddbcc..c49bb0760 100644 --- a/packages/server/src/db/schema/deployment.ts +++ b/packages/server/src/db/schema/deployment.ts @@ -34,6 +34,12 @@ export const deployments = pgTable("deployment", { status: deploymentStatus("status").default("running"), logPath: text("logPath").notNull(), pid: text("pid"), + applicationBuildServerId: text("applicationBuildServerId").references( + () => server.serverId, + { + onDelete: "cascade", + }, + ), applicationId: text("applicationId").references( () => applications.applicationId, { onDelete: "cascade" }, diff --git a/packages/server/src/services/application.ts b/packages/server/src/services/application.ts index 1891f9b6b..e2c38a9fa 100644 --- a/packages/server/src/services/application.ts +++ b/packages/server/src/services/application.ts @@ -13,35 +13,23 @@ import { } from "@dokploy/server/utils/builders"; import { sendBuildErrorNotifications } from "@dokploy/server/utils/notifications/build-error"; import { sendBuildSuccessNotifications } from "@dokploy/server/utils/notifications/build-success"; -import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync"; import { - cloneBitbucketRepository, - getBitbucketCloneCommand, -} from "@dokploy/server/utils/providers/bitbucket"; + execAsync, + execAsyncRemote, +} from "@dokploy/server/utils/process/execAsync"; +import { cloneBitbucketRepository } from "@dokploy/server/utils/providers/bitbucket"; import { buildDocker, buildRemoteDocker, } from "@dokploy/server/utils/providers/docker"; -import { - cloneGitRepository, - getCustomGitCloneCommand, -} from "@dokploy/server/utils/providers/git"; -import { - cloneGiteaRepository, - getGiteaCloneCommand, -} from "@dokploy/server/utils/providers/gitea"; -import { - cloneGithubRepository, - getGithubCloneCommand, -} from "@dokploy/server/utils/providers/github"; -import { - cloneGitlabRepository, - getGitlabCloneCommand, -} from "@dokploy/server/utils/providers/gitlab"; +import { cloneGitRepository } from "@dokploy/server/utils/providers/git"; +import { cloneGiteaRepository } from "@dokploy/server/utils/providers/gitea"; +import { cloneGithubRepository } from "@dokploy/server/utils/providers/github"; +import { cloneGitlabRepository } from "@dokploy/server/utils/providers/gitlab"; import { createTraefikConfig } from "@dokploy/server/utils/traefik/application"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; -import { encodeBase64 } from "../utils/docker/utils"; +import { cleanUpSystemPrune, encodeBase64 } from "../utils/docker/utils"; import { getDokployUrl } from "./admin"; import { createDeployment, @@ -192,43 +180,43 @@ export const deployApplication = async ({ }); try { + let command = "set -e;"; if (application.sourceType === "github") { - await cloneGithubRepository({ - ...application, - logPath: deployment.logPath, - }); - await buildApplication(application, deployment.logPath); + command += await cloneGithubRepository(application); } else if (application.sourceType === "gitlab") { - await cloneGitlabRepository(application, deployment.logPath); - await buildApplication(application, deployment.logPath); + command += await cloneGitlabRepository(application); } else if (application.sourceType === "gitea") { - await cloneGiteaRepository(application, deployment.logPath); - await buildApplication(application, deployment.logPath); + command += await cloneGiteaRepository(application); } else if (application.sourceType === "bitbucket") { - await cloneBitbucketRepository(application, deployment.logPath); - await buildApplication(application, deployment.logPath); - } else if (application.sourceType === "docker") { - await buildDocker(application, deployment.logPath); + command += await cloneBitbucketRepository(application); } else if (application.sourceType === "git") { - await cloneGitRepository(application, deployment.logPath); - await buildApplication(application, deployment.logPath); + command += await cloneGitRepository(application); } else if (application.sourceType === "drop") { await buildApplication(application, deployment.logPath); } + command += getBuildCommand(application); + const commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`; + if (application.serverId) { + await execAsyncRemote(application.serverId, commandWithLog); + } else { + await execAsync(commandWithLog); + } + + await mechanizeDockerContainer(application); await updateDeploymentStatus(deployment.deploymentId, "done"); await updateApplicationStatus(applicationId, "done"); - if (application.rollbackActive) { - const tagImage = - application.sourceType === "docker" - ? application.dockerImage - : application.appName; - await createRollback({ - appName: tagImage || "", - deploymentId: deployment.deploymentId, - }); - } + // if (application.rollbackActive) { + // const tagImage = + // application.sourceType === "docker" + // ? application.dockerImage + // : application.appName; + // await createRollback({ + // appName: tagImage || "", + // deploymentId: deployment.deploymentId, + // }); + // } await sendBuildSuccessNotifications({ projectName: application.environment.project.name, @@ -239,6 +227,12 @@ export const deployApplication = async ({ domains: application.domains, }); } catch (error) { + const command = `echo "Error occurred ❌, check the logs for details." >> ${deployment.logPath};`; + if (application.serverId) { + await execAsyncRemote(application.serverId, command); + } else { + await execAsync(command); + } await updateDeploymentStatus(deployment.deploymentId, "error"); await updateApplicationStatus(applicationId, "error"); @@ -254,7 +248,6 @@ export const deployApplication = async ({ throw error; } - return true; }; @@ -276,129 +269,21 @@ export const rebuildApplication = async ({ }); try { - if (application.sourceType === "github") { - await buildApplication(application, deployment.logPath); - } else if (application.sourceType === "gitlab") { - await buildApplication(application, deployment.logPath); - } else if (application.sourceType === "bitbucket") { - await buildApplication(application, deployment.logPath); - } else if (application.sourceType === "docker") { - await buildDocker(application, deployment.logPath); - } else if (application.sourceType === "git") { - await buildApplication(application, deployment.logPath); - } else if (application.sourceType === "drop") { - await buildApplication(application, deployment.logPath); - } - await updateDeploymentStatus(deployment.deploymentId, "done"); - await updateApplicationStatus(applicationId, "done"); - } catch (error) { - await updateDeploymentStatus(deployment.deploymentId, "error"); - await updateApplicationStatus(applicationId, "error"); - throw error; - } - - return true; -}; - -export const deployRemoteApplication = async ({ - applicationId, - titleLog = "Manual deployment", - descriptionLog = "", -}: { - applicationId: string; - titleLog: string; - descriptionLog: string; -}) => { - const application = await findApplicationById(applicationId); - - const buildLink = `${await getDokployUrl()}/dashboard/project/${application.environment.projectId}/environment/${application.environmentId}/services/application/${application.applicationId}?tab=deployments`; - const deployment = await createDeployment({ - applicationId: applicationId, - title: titleLog, - description: descriptionLog, - }); - - try { + let command = "set -e;"; + // Check case for docker only + command += getBuildCommand(application); + const commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`; if (application.serverId) { - let command = "set -e;"; - if (application.sourceType === "github") { - command += await getGithubCloneCommand({ - ...application, - serverId: application.serverId, - logPath: deployment.logPath, - }); - } else if (application.sourceType === "gitlab") { - command += await getGitlabCloneCommand(application, deployment.logPath); - } else if (application.sourceType === "bitbucket") { - command += await getBitbucketCloneCommand( - application, - deployment.logPath, - ); - } else if (application.sourceType === "gitea") { - command += await getGiteaCloneCommand(application, deployment.logPath); - } else if (application.sourceType === "git") { - command += await getCustomGitCloneCommand( - application, - deployment.logPath, - ); - } else if (application.sourceType === "docker") { - command += await buildRemoteDocker(application, deployment.logPath); - } - - if (application.sourceType !== "docker") { - command += getBuildCommand(application, deployment.logPath); - } - await execAsyncRemote(application.serverId, command); - await mechanizeDockerContainer(application); + await execAsyncRemote(application.serverId, commandWithLog); + } else { + await execAsync(commandWithLog); } - + await mechanizeDockerContainer(application); await updateDeploymentStatus(deployment.deploymentId, "done"); await updateApplicationStatus(applicationId, "done"); - - if (application.rollbackActive) { - const tagImage = - application.sourceType === "docker" - ? application.dockerImage - : application.appName; - await createRollback({ - appName: tagImage || "", - deploymentId: deployment.deploymentId, - }); - } - - await sendBuildSuccessNotifications({ - projectName: application.environment.project.name, - applicationName: application.name, - applicationType: "application", - buildLink, - organizationId: application.environment.project.organizationId, - domains: application.domains, - }); } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - - const encodedContent = encodeBase64(errorMessage); - - await execAsyncRemote( - application.serverId, - ` - echo "\n\n===================================EXTRA LOGS============================================" >> ${deployment.logPath}; - echo "Error occurred ❌, check the logs for details." >> ${deployment.logPath}; - echo "${encodedContent}" | base64 -d >> "${deployment.logPath}";`, - ); - await updateDeploymentStatus(deployment.deploymentId, "error"); await updateApplicationStatus(applicationId, "error"); - - await sendBuildErrorNotifications({ - projectName: application.environment.project.name, - applicationName: application.name, - applicationType: "application", - errorMessage: `Please check the logs for details: ${errorMessage}`, - buildLink, - organizationId: application.environment.project.organizationId, - }); - throw error; } @@ -586,7 +471,7 @@ export const deployRemotePreviewApplication = async ({ if (application.serverId) { let command = "set -e;"; if (application.sourceType === "github") { - command += await getGithubCloneCommand({ + command += await cloneGithubRepository({ ...application, appName: previewDeployment.appName, branch: previewDeployment.branch, @@ -629,53 +514,6 @@ export const deployRemotePreviewApplication = async ({ return true; }; -export const rebuildRemoteApplication = async ({ - applicationId, - titleLog = "Rebuild deployment", - descriptionLog = "", -}: { - applicationId: string; - titleLog: string; - descriptionLog: string; -}) => { - const application = await findApplicationById(applicationId); - - const deployment = await createDeployment({ - applicationId: applicationId, - title: titleLog, - description: descriptionLog, - }); - - try { - if (application.serverId) { - if (application.sourceType !== "docker") { - let command = "set -e;"; - command += getBuildCommand(application, deployment.logPath); - await execAsyncRemote(application.serverId, command); - } - await mechanizeDockerContainer(application); - } - await updateDeploymentStatus(deployment.deploymentId, "done"); - await updateApplicationStatus(applicationId, "done"); - } catch (error) { - // @ts-ignore - const encodedContent = encodeBase64(error?.message); - - await execAsyncRemote( - application.serverId, - ` - echo "\n\n===================================EXTRA LOGS============================================" >> ${deployment.logPath}; - echo "Error occurred ❌, check the logs for details." >> ${deployment.logPath}; - echo "${encodedContent}" | base64 -d >> "${deployment.logPath}";`, - ); - await updateDeploymentStatus(deployment.deploymentId, "error"); - await updateApplicationStatus(applicationId, "error"); - throw error; - } - - return true; -}; - export const getApplicationStats = async (appName: string) => { const filter = { status: ["running"], diff --git a/packages/server/src/services/compose.ts b/packages/server/src/services/compose.ts index 1436c52cc..4b96f443d 100644 --- a/packages/server/src/services/compose.ts +++ b/packages/server/src/services/compose.ts @@ -7,14 +7,10 @@ import { cleanAppName, compose, } from "@dokploy/server/db/schema"; -import { - buildCompose, - getBuildComposeCommand, -} from "@dokploy/server/utils/builders/compose"; +import { getBuildComposeCommand } from "@dokploy/server/utils/builders/compose"; import { randomizeSpecificationFile } from "@dokploy/server/utils/docker/compose"; import { cloneCompose, - cloneComposeRemote, loadDockerCompose, loadDockerComposeRemote, } from "@dokploy/server/utils/docker/domain"; @@ -25,33 +21,14 @@ import { execAsync, execAsyncRemote, } from "@dokploy/server/utils/process/execAsync"; -import { - cloneBitbucketRepository, - getBitbucketCloneCommand, -} from "@dokploy/server/utils/providers/bitbucket"; -import { - cloneGitRepository, - getCustomGitCloneCommand, -} from "@dokploy/server/utils/providers/git"; -import { - cloneGiteaRepository, - getGiteaCloneCommand, -} from "@dokploy/server/utils/providers/gitea"; -import { - cloneGithubRepository, - getGithubCloneCommand, -} from "@dokploy/server/utils/providers/github"; -import { - cloneGitlabRepository, - getGitlabCloneCommand, -} from "@dokploy/server/utils/providers/gitlab"; -import { - createComposeFile, - getCreateComposeFileCommand, -} from "@dokploy/server/utils/providers/raw"; +import { cloneBitbucketRepository } from "@dokploy/server/utils/providers/bitbucket"; +import { cloneGitRepository } from "@dokploy/server/utils/providers/git"; +import { cloneGiteaRepository } from "@dokploy/server/utils/providers/gitea"; +import { cloneGithubRepository } from "@dokploy/server/utils/providers/github"; +import { cloneGitlabRepository } from "@dokploy/server/utils/providers/gitlab"; +import { getCreateComposeFileCommand } from "@dokploy/server/utils/providers/raw"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; -import { encodeBase64 } from "../utils/docker/utils"; import { getDokployUrl } from "./admin"; import { createDeploymentCompose, updateDeploymentStatus } from "./deployment"; import { validUniqueServerAppName } from "./project"; @@ -163,10 +140,11 @@ export const loadServices = async ( const compose = await findComposeById(composeId); if (type === "fetch") { + const command = await cloneCompose(compose); if (compose.serverId) { - await cloneComposeRemote(compose); + await execAsyncRemote(compose.serverId, command); } else { - await cloneCompose(compose); + await execAsync(command); } } @@ -235,24 +213,33 @@ export const deployCompose = async ({ }); try { + const entity = { + ...compose, + type: "compose" as const, + }; + let command = "set -e;"; if (compose.sourceType === "github") { - await cloneGithubRepository({ - ...compose, - logPath: deployment.logPath, - type: "compose", - }); + command += await cloneGithubRepository(entity); } else if (compose.sourceType === "gitlab") { - await cloneGitlabRepository(compose, deployment.logPath, true); + command += await cloneGitlabRepository(entity); } else if (compose.sourceType === "bitbucket") { - await cloneBitbucketRepository(compose, deployment.logPath, true); + command += await cloneBitbucketRepository(entity); } else if (compose.sourceType === "git") { - await cloneGitRepository(compose, deployment.logPath, true); + command += await cloneGitRepository(entity); } else if (compose.sourceType === "gitea") { - await cloneGiteaRepository(compose, deployment.logPath, true); + command += await cloneGiteaRepository(entity); } else if (compose.sourceType === "raw") { - await createComposeFile(compose, deployment.logPath); + command += getCreateComposeFileCommand(entity); } - await buildCompose(compose, deployment.logPath); + + command += await getBuildComposeCommand(entity); + const commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`; + if (compose.serverId) { + await execAsyncRemote(compose.serverId, commandWithLog); + } else { + await execAsync(commandWithLog); + } + await updateDeploymentStatus(deployment.deploymentId, "done"); await updateCompose(composeId, { composeStatus: "done", @@ -302,154 +289,16 @@ export const rebuildCompose = async ({ }); try { + let command = "set -e;"; if (compose.sourceType === "raw") { - await createComposeFile(compose, deployment.logPath); + command += getCreateComposeFileCommand(compose); } - await buildCompose(compose, deployment.logPath); - - await updateDeploymentStatus(deployment.deploymentId, "done"); - await updateCompose(composeId, { - composeStatus: "done", - }); - } catch (error) { - await updateDeploymentStatus(deployment.deploymentId, "error"); - await updateCompose(composeId, { - composeStatus: "error", - }); - throw error; - } - - return true; -}; - -export const deployRemoteCompose = async ({ - composeId, - titleLog = "Manual deployment", - descriptionLog = "", -}: { - composeId: string; - titleLog: string; - descriptionLog: string; -}) => { - const compose = await findComposeById(composeId); - - const buildLink = `${await getDokployUrl()}/dashboard/project/${ - compose.environment.projectId - }/environment/${compose.environmentId}/services/compose/${compose.composeId}?tab=deployments`; - const deployment = await createDeploymentCompose({ - composeId: composeId, - title: titleLog, - description: descriptionLog, - }); - try { + command += await getBuildComposeCommand(compose); + const commandWithLog = `(${command}) >> ${deployment.logPath} 2>&1`; if (compose.serverId) { - let command = "set -e;"; - - if (compose.sourceType === "github") { - command += await getGithubCloneCommand({ - ...compose, - logPath: deployment.logPath, - type: "compose", - serverId: compose.serverId, - }); - } else if (compose.sourceType === "gitlab") { - command += await getGitlabCloneCommand( - compose, - deployment.logPath, - true, - ); - } else if (compose.sourceType === "bitbucket") { - command += await getBitbucketCloneCommand( - compose, - deployment.logPath, - true, - ); - } else if (compose.sourceType === "git") { - command += await getCustomGitCloneCommand( - compose, - deployment.logPath, - true, - ); - console.log(command); - } else if (compose.sourceType === "raw") { - command += getCreateComposeFileCommand(compose, deployment.logPath); - } else if (compose.sourceType === "gitea") { - command += await getGiteaCloneCommand( - compose, - deployment.logPath, - true, - ); - } - - await execAsyncRemote(compose.serverId, command); - await getBuildComposeCommand(compose, deployment.logPath); - } - - await updateDeploymentStatus(deployment.deploymentId, "done"); - await updateCompose(composeId, { - composeStatus: "done", - }); - - await sendBuildSuccessNotifications({ - projectName: compose.environment.project.name, - applicationName: compose.name, - applicationType: "compose", - buildLink, - organizationId: compose.environment.project.organizationId, - domains: compose.domains, - }); - } catch (error) { - // @ts-ignore - const encodedContent = encodeBase64(error?.message); - - await execAsyncRemote( - compose.serverId, - ` - echo "\n\n===================================EXTRA LOGS============================================" >> ${deployment.logPath}; - echo "Error occurred ❌, check the logs for details." >> ${deployment.logPath}; - echo "${encodedContent}" | base64 -d >> "${deployment.logPath}";`, - ); - await updateDeploymentStatus(deployment.deploymentId, "error"); - await updateCompose(composeId, { - composeStatus: "error", - }); - await sendBuildErrorNotifications({ - projectName: compose.environment.project.name, - applicationName: compose.name, - applicationType: "compose", - // @ts-ignore - errorMessage: error?.message || "Error building", - buildLink, - organizationId: compose.environment.project.organizationId, - }); - throw error; - } -}; - -export const rebuildRemoteCompose = async ({ - composeId, - titleLog = "Rebuild deployment", - descriptionLog = "", -}: { - composeId: string; - titleLog: string; - descriptionLog: string; -}) => { - const compose = await findComposeById(composeId); - - const deployment = await createDeploymentCompose({ - composeId: composeId, - title: titleLog, - description: descriptionLog, - }); - - try { - if (compose.sourceType === "raw") { - const command = getCreateComposeFileCommand(compose, deployment.logPath); - await execAsyncRemote(compose.serverId, command); - } - if (compose.serverId) { - await getBuildComposeCommand(compose, deployment.logPath); + await execAsyncRemote(compose.serverId, commandWithLog); + } else { + await execAsync(commandWithLog); } await updateDeploymentStatus(deployment.deploymentId, "done"); @@ -457,16 +306,6 @@ export const rebuildRemoteCompose = async ({ composeStatus: "done", }); } catch (error) { - // @ts-ignore - const encodedContent = encodeBase64(error?.message); - - await execAsyncRemote( - compose.serverId, - ` - echo "\n\n===================================EXTRA LOGS============================================" >> ${deployment.logPath}; - echo "Error occurred ❌, check the logs for details." >> ${deployment.logPath}; - echo "${encodedContent}" | base64 -d >> "${deployment.logPath}";`, - ); await updateDeploymentStatus(deployment.deploymentId, "error"); await updateCompose(composeId, { composeStatus: "error", diff --git a/packages/server/src/services/deployment.ts b/packages/server/src/services/deployment.ts index ed03b32fc..95d543dd0 100644 --- a/packages/server/src/services/deployment.ts +++ b/packages/server/src/services/deployment.ts @@ -74,20 +74,21 @@ export const createDeployment = async ( >, ) => { const application = await findApplicationById(deployment.applicationId); - try { await removeLastTenDeployments( deployment.applicationId, "application", application.serverId, ); - const { LOGS_PATH } = paths(!!application.serverId); + const serverId = application.serverId; + + const { LOGS_PATH } = paths(!!serverId); const formattedDateTime = format(new Date(), "yyyy-MM-dd:HH:mm:ss"); const fileName = `${application.appName}-${formattedDateTime}.log`; const logFilePath = path.join(LOGS_PATH, application.appName, fileName); - if (application.serverId) { - const server = await findServerById(application.serverId); + if (serverId) { + const server = await findServerById(serverId); const command = ` mkdir -p ${LOGS_PATH}/${application.appName}; @@ -99,7 +100,7 @@ export const createDeployment = async ( await fsPromises.mkdir(path.join(LOGS_PATH, application.appName), { recursive: true, }); - await fsPromises.writeFile(logFilePath, "Initializing deployment"); + await fsPromises.writeFile(logFilePath, "Initializing deployment\n"); } const deploymentCreate = await db @@ -111,6 +112,7 @@ export const createDeployment = async ( logPath: logFilePath, description: deployment.description || "", startedAt: new Date().toISOString(), + // applicationBuildServerId: application.serverBuildId, }) .returning(); if (deploymentCreate.length === 0 || !deploymentCreate[0]) { @@ -249,7 +251,7 @@ export const createDeploymentCompose = async ( const command = ` mkdir -p ${LOGS_PATH}/${compose.appName}; -echo "Initializing deployment" >> ${logFilePath}; +echo "Initializing deployment\n" >> ${logFilePath}; `; await execAsyncRemote(server.serverId, command); @@ -257,7 +259,7 @@ echo "Initializing deployment" >> ${logFilePath}; await fsPromises.mkdir(path.join(LOGS_PATH, compose.appName), { recursive: true, }); - await fsPromises.writeFile(logFilePath, "Initializing deployment"); + await fsPromises.writeFile(logFilePath, "Initializing deployment\n"); } const deploymentCreate = await db diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts index 667b46b74..6b26a0d1c 100644 --- a/packages/server/src/utils/builders/compose.ts +++ b/packages/server/src/utils/builders/compose.ts @@ -17,7 +17,7 @@ import { getEnviromentVariablesObject, prepareEnvironmentVariables, } from "../docker/utils"; -import { execAsync, execAsyncRemote } from "../process/execAsync"; +import { execAsync } from "../process/execAsync"; import { spawnAsync } from "../process/spawnAsync"; export type ComposeNested = InferResultType< @@ -96,22 +96,15 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => { } }; -export const getBuildComposeCommand = async ( - compose: ComposeNested, - logPath: string, -) => { - const { COMPOSE_PATH } = paths(true); +export const getBuildComposeCommand = async (compose: ComposeNested) => { + const { COMPOSE_PATH } = paths(!!compose.serverId); const { sourceType, appName, mounts, composeType, domains } = compose; const command = createCommand(compose); const envCommand = getCreateEnvFileCommand(compose); const projectPath = join(COMPOSE_PATH, compose.appName, "code"); const exportEnvCommand = getExportEnvCommand(compose); - const newCompose = await writeDomainsToComposeRemote( - compose, - domains, - logPath, - ); + const newCompose = await writeDomainsToComposeRemote(compose, domains); const logContent = ` App Name: ${appName} Build Compose 🐳 @@ -133,7 +126,7 @@ Compose Type: ${composeType} ✅`; const bashCommand = ` set -e { - echo "${logBox}" >> "${logPath}" + echo "${logBox}"; ${newCompose} @@ -143,17 +136,18 @@ Compose Type: ${composeType} ✅`; ${exportEnvCommand} ${compose.isolatedDeployment ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}` : ""} - docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; } + docker ${command.split(" ").join(" ")} 2>&1 || { echo "Error: ❌ Docker command failed"; exit 1; } ${compose.isolatedDeployment ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""} - echo "Docker Compose Deployed: ✅" >> "${logPath}" + echo "Docker Compose Deployed: ✅"; } || { - echo "Error: ❌ Script execution failed" >> "${logPath}" + echo "Error: ❌ Script execution failed"; exit 1 } `; - return await execAsyncRemote(compose.serverId, bashCommand); + return bashCommand; + // return await execAsyncRemote(compose.serverId, bashCommand); }; const sanitizeCommand = (command: string) => { @@ -216,7 +210,7 @@ const createEnvFile = (compose: ComposeNested) => { }; export const getCreateEnvFileCommand = (compose: ComposeNested) => { - const { COMPOSE_PATH } = paths(true); + const { COMPOSE_PATH } = paths(!!compose.serverId); const { env, composePath, appName } = compose; const composeFilePath = join(COMPOSE_PATH, appName, "code", composePath) || diff --git a/packages/server/src/utils/builders/docker-file.ts b/packages/server/src/utils/builders/docker-file.ts index b5c2b59c3..4636cb22c 100644 --- a/packages/server/src/utils/builders/docker-file.ts +++ b/packages/server/src/utils/builders/docker-file.ts @@ -100,10 +100,7 @@ export const buildCustomDocker = async ( } }; -export const getDockerCommand = ( - application: ApplicationNested, - logPath: string, -) => { +export const getDockerCommand = (application: ApplicationNested) => { const { appName, env, @@ -176,17 +173,17 @@ export const getDockerCommand = ( } command += ` -echo "Building ${appName}" >> ${logPath}; -cd ${dockerContextPath} >> ${logPath} 2>> ${logPath} || { - echo "❌ The path ${dockerContextPath} does not exist" >> ${logPath}; +echo "Building ${appName}" ; +cd ${dockerContextPath} || { + echo "❌ The path ${dockerContextPath} does not exist" ; exit 1; } -${joinedSecrets} docker ${commandArgs.join(" ")} >> ${logPath} 2>> ${logPath} || { - echo "❌ Docker build failed" >> ${logPath}; +${joinedSecrets} docker ${commandArgs.join(" ")} || { + echo "❌ Docker build failed" ; exit 1; } -echo "✅ Docker build completed." >> ${logPath}; +echo "✅ Docker build completed." ; `; return command; diff --git a/packages/server/src/utils/builders/heroku.ts b/packages/server/src/utils/builders/heroku.ts index 3306f2fc2..a0a8da153 100644 --- a/packages/server/src/utils/builders/heroku.ts +++ b/packages/server/src/utils/builders/heroku.ts @@ -45,10 +45,7 @@ export const buildHeroku = async ( } }; -export const getHerokuCommand = ( - application: ApplicationNested, - logPath: string, -) => { +export const getHerokuCommand = (application: ApplicationNested) => { const { env, appName, cleanCache } = application; const buildAppDirectory = getBuildAppDirectory(application); @@ -77,12 +74,12 @@ export const getHerokuCommand = ( const command = `pack ${args.join(" ")}`; const bashCommand = ` -echo "Starting heroku build..." >> ${logPath}; -${command} >> ${logPath} 2>> ${logPath} || { - echo "❌ Heroku build failed" >> ${logPath}; +echo "Starting heroku build..." ; +${command} || { + echo "❌ Heroku build failed" ; exit 1; } -echo "✅ Heroku build completed." >> ${logPath}; +echo "✅ Heroku build completed." ; `; return bashCommand; diff --git a/packages/server/src/utils/builders/index.ts b/packages/server/src/utils/builders/index.ts index 5ae0704c5..35172789c 100644 --- a/packages/server/src/utils/builders/index.ts +++ b/packages/server/src/utils/builders/index.ts @@ -76,34 +76,31 @@ export const buildApplication = async ( } }; -export const getBuildCommand = ( - application: ApplicationNested, - logPath: string, -) => { +export const getBuildCommand = (application: ApplicationNested) => { let command = ""; const { buildType, registry } = application; switch (buildType) { case "nixpacks": - command = getNixpacksCommand(application, logPath); + command = getNixpacksCommand(application); break; case "heroku_buildpacks": - command = getHerokuCommand(application, logPath); + command = getHerokuCommand(application); break; case "paketo_buildpacks": - command = getPaketoCommand(application, logPath); + command = getPaketoCommand(application); break; case "static": - command = getStaticCommand(application, logPath); + command = getStaticCommand(application); break; case "dockerfile": - command = getDockerCommand(application, logPath); + command = getDockerCommand(application); break; case "railpack": - command = getRailpackCommand(application, logPath); + command = getRailpackCommand(application); break; } if (registry) { - command += uploadImageRemoteCommand(application, logPath); + command += uploadImageRemoteCommand(application); } return command; diff --git a/packages/server/src/utils/builders/nixpacks.ts b/packages/server/src/utils/builders/nixpacks.ts index 76905d0e7..705539f06 100644 --- a/packages/server/src/utils/builders/nixpacks.ts +++ b/packages/server/src/utils/builders/nixpacks.ts @@ -92,10 +92,7 @@ export const buildNixpacks = async ( } }; -export const getNixpacksCommand = ( - application: ApplicationNested, - logPath: string, -) => { +export const getNixpacksCommand = (application: ApplicationNested) => { const { env, appName, publishDirectory, cleanCache } = application; const buildAppDirectory = getBuildAppDirectory(application); @@ -121,13 +118,13 @@ export const getNixpacksCommand = ( args.push("--no-error-without-start"); } const command = `nixpacks ${args.join(" ")}`; - let bashCommand = ` -echo "Starting nixpacks build..." >> ${logPath}; -${command} >> ${logPath} 2>> ${logPath} || { - echo "❌ Nixpacks build failed" >> ${logPath}; - exit 1; -} -echo "✅ Nixpacks build completed." >> ${logPath}; + const bashCommand = ` + echo "Starting nixpacks build..." ; + ${command} || { + echo "❌ Nixpacks build failed" ; + exit 1; + } + echo "✅ Nixpacks build completed." ; `; /* @@ -135,23 +132,23 @@ echo "✅ Nixpacks build completed." >> ${logPath}; and copy the artifacts on the host filesystem. Then, remove the container and create a static build. */ - if (publishDirectory) { - const localPath = path.join(buildAppDirectory, publishDirectory); - const isDirectory = - publishDirectory.endsWith("/") || !path.extname(publishDirectory); + // if (publishDirectory) { + // const localPath = path.join(buildAppDirectory, publishDirectory); + // const isDirectory = + // publishDirectory.endsWith("/") || !path.extname(publishDirectory); - bashCommand += ` -docker create --name ${buildContainerId} ${appName} -mkdir -p ${localPath} -docker cp ${buildContainerId}:/app/${publishDirectory}${isDirectory ? "/." : ""} ${path.join(buildAppDirectory, publishDirectory)} >> ${logPath} 2>> ${logPath} || { - docker rm ${buildContainerId} - echo "❌ Copying ${publishDirectory} to ${path.join(buildAppDirectory, publishDirectory)} failed" >> ${logPath}; - exit 1; -} -docker rm ${buildContainerId} -${getStaticCommand(application, logPath)} - `; - } + // bashCommand += ` + // docker create --name ${buildContainerId} ${appName} + // mkdir -p ${localPath} + // docker cp ${buildContainerId}:/app/${publishDirectory}${isDirectory ? "/." : ""} ${path.join(buildAppDirectory, publishDirectory)} || { + // docker rm ${buildContainerId} + // echo "❌ Copying ${publishDirectory} to ${path.join(buildAppDirectory, publishDirectory)} failed" ; + // exit 1; + // } + // docker rm ${buildContainerId} + // ${getStaticCommand(application)} + // `; + // } return bashCommand; }; diff --git a/packages/server/src/utils/builders/paketo.ts b/packages/server/src/utils/builders/paketo.ts index b95a1bb31..51e2301f9 100644 --- a/packages/server/src/utils/builders/paketo.ts +++ b/packages/server/src/utils/builders/paketo.ts @@ -44,10 +44,7 @@ export const buildPaketo = async ( } }; -export const getPaketoCommand = ( - application: ApplicationNested, - logPath: string, -) => { +export const getPaketoCommand = (application: ApplicationNested) => { const { env, appName, cleanCache } = application; const buildAppDirectory = getBuildAppDirectory(application); @@ -76,12 +73,12 @@ export const getPaketoCommand = ( const command = `pack ${args.join(" ")}`; const bashCommand = ` -echo "Starting Paketo build..." >> ${logPath}; -${command} >> ${logPath} 2>> ${logPath} || { - echo "❌ Paketo build failed" >> ${logPath}; +echo "Starting Paketo build..." ; +${command} || { + echo "❌ Paketo build failed" ; exit 1; } -echo "✅ Paketo build completed." >> ${logPath}; +echo "✅ Paketo build completed." ; `; return bashCommand; diff --git a/packages/server/src/utils/builders/railpack.ts b/packages/server/src/utils/builders/railpack.ts index 4adc9ca1c..822257773 100644 --- a/packages/server/src/utils/builders/railpack.ts +++ b/packages/server/src/utils/builders/railpack.ts @@ -116,10 +116,7 @@ export const buildRailpack = async ( } }; -export const getRailpackCommand = ( - application: ApplicationNested, - logPath: string, -) => { +export const getRailpackCommand = (application: ApplicationNested) => { const { env, appName, cleanCache } = application; const buildAppDirectory = getBuildAppDirectory(application); const envVariables = prepareEnvironmentVariables( @@ -183,21 +180,21 @@ export const getRailpackCommand = ( docker buildx create --use --name builder-containerd --driver docker-container || true docker buildx use builder-containerd -echo "Preparing Railpack build plan..." >> "${logPath}"; -railpack ${prepareArgs.join(" ")} >> ${logPath} 2>> ${logPath} || { - echo "❌ Railpack prepare failed" >> ${logPath}; +echo "Preparing Railpack build plan..." ; +railpack ${prepareArgs.join(" ")} || { + echo "❌ Railpack prepare failed" ; exit 1; } -echo "✅ Railpack prepare completed." >> ${logPath}; +echo "✅ Railpack prepare completed." ; -echo "Building with Railpack frontend..." >> "${logPath}"; +echo "Building with Railpack frontend..." ; # Export environment variables for secrets ${exportEnvs.join("\n")} -docker ${buildArgs.join(" ")} >> ${logPath} 2>> ${logPath} || { - echo "❌ Railpack build failed" >> ${logPath}; +docker ${buildArgs.join(" ")} || { + echo "❌ Railpack build failed" ; exit 1; } -echo "✅ Railpack build completed." >> ${logPath}; +echo "✅ Railpack build completed." ; docker buildx rm builder-containerd `; diff --git a/packages/server/src/utils/builders/static.ts b/packages/server/src/utils/builders/static.ts index e59faa711..5e1f10cc3 100644 --- a/packages/server/src/utils/builders/static.ts +++ b/packages/server/src/utils/builders/static.ts @@ -83,10 +83,7 @@ export const buildStatic = async ( } }; -export const getStaticCommand = ( - application: ApplicationNested, - logPath: string, -) => { +export const getStaticCommand = (application: ApplicationNested) => { const { publishDirectory } = application; const buildAppDirectory = getBuildAppDirectory(application); @@ -100,13 +97,10 @@ export const getStaticCommand = ( ].join("\n"), ); - command += getDockerCommand( - { - ...application, - buildType: "dockerfile", - dockerfile: "Dockerfile", - }, - logPath, - ); + command += getDockerCommand({ + ...application, + buildType: "dockerfile", + dockerfile: "Dockerfile", + }); return command; }; diff --git a/packages/server/src/utils/cluster/upload.ts b/packages/server/src/utils/cluster/upload.ts index c13a2701c..6a2dfd66f 100644 --- a/packages/server/src/utils/cluster/upload.ts +++ b/packages/server/src/utils/cluster/upload.ts @@ -59,10 +59,7 @@ export const uploadImage = async ( } }; -export const uploadImageRemoteCommand = ( - application: ApplicationNested, - logPath: string, -) => { +export const uploadImageRemoteCommand = (application: ApplicationNested) => { const registry = application.registry; if (!registry) { @@ -82,22 +79,22 @@ export const uploadImageRemoteCommand = ( try { const command = ` - echo "📦 [Enabled Registry] Uploading image to '${registry.registryType}' | '${registryTag}'" >> ${logPath}; - echo "${registry.password}" | docker login ${finalURL} -u ${registry.username} --password-stdin >> ${logPath} 2>> ${logPath} || { - echo "❌ DockerHub Failed" >> ${logPath}; + echo "📦 [Enabled Registry] Uploading image to '${registry.registryType}' | '${registryTag}'" ; + echo "${registry.password}" | docker login ${finalURL} -u ${registry.username} --password-stdin || { + echo "❌ DockerHub Failed" ; exit 1; } - echo "✅ Registry Login Success" >> ${logPath}; - docker tag ${imageName} ${registryTag} >> ${logPath} 2>> ${logPath} || { - echo "❌ Error tagging image" >> ${logPath}; + echo "✅ Registry Login Success" ; + docker tag ${imageName} ${registryTag} || { + echo "❌ Error tagging image" ; exit 1; } - echo "✅ Image Tagged" >> ${logPath}; - docker push ${registryTag} 2>> ${logPath} || { - echo "❌ Error pushing image" >> ${logPath}; + echo "✅ Image Tagged" ; + docker push ${registryTag} || { + echo "❌ Error pushing image" ; exit 1; } - echo "✅ Image Pushed" >> ${logPath}; + echo "✅ Image Pushed" ; `; return command; } catch (error) { diff --git a/packages/server/src/utils/docker/collision.ts b/packages/server/src/utils/docker/collision.ts index 9752100ca..88d20d4d8 100644 --- a/packages/server/src/utils/docker/collision.ts +++ b/packages/server/src/utils/docker/collision.ts @@ -1,11 +1,11 @@ import { findComposeById } from "@dokploy/server/services/compose"; import { stringify } from "yaml"; +import { execAsync, execAsyncRemote } from "../process/execAsync"; import { addAppNameToAllServiceNames } from "./collision/root-network"; import { generateRandomHash } from "./compose"; import { addSuffixToAllVolumes } from "./compose/volume"; import { cloneCompose, - cloneComposeRemote, loadDockerCompose, loadDockerComposeRemote, } from "./domain"; @@ -31,10 +31,11 @@ export const randomizeIsolatedDeploymentComposeFile = async ( ) => { const compose = await findComposeById(composeId); + const command = await cloneCompose(compose); if (compose.serverId) { - await cloneComposeRemote(compose); + await execAsyncRemote(compose.serverId, command); } else { - await cloneCompose(compose); + await execAsync(command); } let composeData: ComposeSpecification | null; diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts index 7a9521d1d..e8c66e697 100644 --- a/packages/server/src/utils/docker/domain.ts +++ b/packages/server/src/utils/docker/domain.ts @@ -6,30 +6,12 @@ import type { Compose } from "@dokploy/server/services/compose"; import type { Domain } from "@dokploy/server/services/domain"; import { parse, stringify } from "yaml"; import { execAsyncRemote } from "../process/execAsync"; -import { - cloneRawBitbucketRepository, - cloneRawBitbucketRepositoryRemote, -} from "../providers/bitbucket"; -import { - cloneGitRawRepository, - cloneRawGitRepositoryRemote, -} from "../providers/git"; -import { - cloneRawGiteaRepository, - cloneRawGiteaRepositoryRemote, -} from "../providers/gitea"; -import { - cloneRawGithubRepository, - cloneRawGithubRepositoryRemote, -} from "../providers/github"; -import { - cloneRawGitlabRepository, - cloneRawGitlabRepositoryRemote, -} from "../providers/gitlab"; -import { - createComposeFileRaw, - createComposeFileRawRemote, -} from "../providers/raw"; +import { cloneBitbucketRepository } from "../providers/bitbucket"; +import { cloneGitRepository } from "../providers/git"; +import { cloneGiteaRepository } from "../providers/gitea"; +import { cloneGithubRepository } from "../providers/github"; +import { cloneGitlabRepository } from "../providers/gitlab"; +import { getCreateComposeFileCommand } from "../providers/raw"; import { randomizeDeployableSpecificationFile } from "./collision"; import { randomizeSpecificationFile } from "./compose"; import type { @@ -40,35 +22,25 @@ import type { import { encodeBase64 } from "./utils"; export const cloneCompose = async (compose: Compose) => { + let command = "set -e;"; + const entity = { + ...compose, + type: "compose" as const, + }; if (compose.sourceType === "github") { - await cloneRawGithubRepository(compose); + command += await cloneGithubRepository(entity); } else if (compose.sourceType === "gitlab") { - await cloneRawGitlabRepository(compose); + command += await cloneGitlabRepository(entity); } else if (compose.sourceType === "bitbucket") { - await cloneRawBitbucketRepository(compose); + command += await cloneBitbucketRepository(entity); } else if (compose.sourceType === "git") { - await cloneGitRawRepository(compose); + command += await cloneGitRepository(entity); } else if (compose.sourceType === "gitea") { - await cloneRawGiteaRepository(compose); + command += await cloneGiteaRepository(entity); } else if (compose.sourceType === "raw") { - await createComposeFileRaw(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 === "gitea") { - await cloneRawGiteaRepositoryRemote(compose); - } else if (compose.sourceType === "raw") { - await createComposeFileRawRemote(compose); + command += getCreateComposeFileCommand(compose); } + return command; }; export const getComposePath = (compose: Compose) => { @@ -152,7 +124,6 @@ export const writeDomainsToCompose = async ( export const writeDomainsToComposeRemote = async ( compose: Compose, domains: Domain[], - logPath: string, ) => { if (!domains.length) { return ""; @@ -164,7 +135,7 @@ export const writeDomainsToComposeRemote = async ( if (!composeConverted) { return ` -echo "❌ Error: Compose file not found" >> ${logPath}; +echo "❌ Error: Compose file not found"; exit 1; `; } @@ -175,7 +146,7 @@ exit 1; } } catch (error) { // @ts-ignore - return `echo "❌ Has occured an error: ${error?.message || error}" >> ${logPath}; + return `echo "❌ Has occured an error: ${error?.message || error}"; exit 1; `; } diff --git a/packages/server/src/utils/process/execAsync.ts b/packages/server/src/utils/process/execAsync.ts index 84f0701d9..13b06c6c4 100644 --- a/packages/server/src/utils/process/execAsync.ts +++ b/packages/server/src/utils/process/execAsync.ts @@ -116,11 +116,7 @@ export const execAsyncRemote = async ( if (code === 0) { resolve({ stdout, stderr }); } else { - reject( - new Error( - `Command exited with code ${code}. Stderr: ${stderr}, command: ${command}`, - ), - ); + reject(new Error(`Error occurred ❌: ${stderr}`)); } }) .on("data", (data: string) => { diff --git a/packages/server/src/utils/providers/bitbucket.ts b/packages/server/src/utils/providers/bitbucket.ts index ed6cd8c31..0267ec9b3 100644 --- a/packages/server/src/utils/providers/bitbucket.ts +++ b/packages/server/src/utils/providers/bitbucket.ts @@ -1,4 +1,3 @@ -import { createWriteStream } from "node:fs"; import { join } from "node:path"; import { paths } from "@dokploy/server/constants"; import type { @@ -9,12 +8,8 @@ import { type Bitbucket, findBitbucketById, } from "@dokploy/server/services/bitbucket"; -import type { Compose } from "@dokploy/server/services/compose"; import type { InferResultType } from "@dokploy/server/types/with"; import { TRPCError } from "@trpc/server"; -import { recreateDirectory } from "../filesystem/directory"; -import { execAsyncRemote } from "../process/execAsync"; -import { spawnAsync } from "../process/spawnAsync"; export type ApplicationWithBitbucket = InferResultType< "applications", @@ -81,13 +76,16 @@ export const getBitbucketHeaders = (bitbucketProvider: Bitbucket) => { }; }; -export const cloneBitbucketRepository = async ( - entity: ApplicationWithBitbucket | ComposeWithBitbucket, - logPath: string, - isCompose = false, -) => { - const { COMPOSE_PATH, APPLICATIONS_PATH } = paths(); - const writeStream = createWriteStream(logPath, { flags: "a" }); +type BitbucketClone = (ApplicationWithBitbucket | ComposeWithBitbucket) & { + serverId: string | null; + type?: "application" | "compose"; +}; + +export const cloneBitbucketRepository = async ({ + type = "application", + ...entity +}: BitbucketClone) => { + let command = "set -e;"; const { appName, bitbucketRepository, @@ -96,187 +94,24 @@ export const cloneBitbucketRepository = async ( bitbucketId, bitbucket, enableSubmodules, + serverId, } = entity; + const { COMPOSE_PATH, APPLICATIONS_PATH } = paths(!!serverId); if (!bitbucketId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Bitbucket Provider not found", - }); + command += `echo "Error: ❌ Bitbucket Provider not found"; exit 1;`; + return command; } - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; + const basePath = type === "compose" ? COMPOSE_PATH : APPLICATIONS_PATH; const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); + command += `rm -rf ${outputPath};`; + command += `mkdir -p ${outputPath};`; const repoclone = `bitbucket.org/${bitbucketOwner}/${bitbucketRepository}.git`; const cloneUrl = getBitbucketCloneUrl(bitbucket, repoclone); - try { - writeStream.write(`\nCloning Repo ${repoclone} to ${outputPath}: ✅\n`); - const cloneArgs = [ - "clone", - "--branch", - bitbucketBranch!, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - cloneUrl, - outputPath, - "--progress", - ]; - - await spawnAsync("git", cloneArgs, (data) => { - if (writeStream.writable) { - writeStream.write(data); - } - }); - writeStream.write(`\nCloned ${repoclone} to ${outputPath}: ✅\n`); - } catch (error) { - writeStream.write(`ERROR Cloning: ${error}: ❌`); - throw error; - } finally { - writeStream.end(); - } -}; - -export const cloneRawBitbucketRepository = async (entity: Compose) => { - const { COMPOSE_PATH } = paths(); - const { - appName, - bitbucketRepository, - bitbucketOwner, - bitbucketBranch, - bitbucketId, - enableSubmodules, - } = entity; - - 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 = getBitbucketCloneUrl(bitbucketProvider, repoclone); - - try { - const cloneArgs = [ - "clone", - "--branch", - bitbucketBranch!, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - cloneUrl, - outputPath, - "--progress", - ]; - - await spawnAsync("git", cloneArgs); - } catch (error) { - throw error; - } -}; - -export const cloneRawBitbucketRepositoryRemote = async (compose: Compose) => { - const { COMPOSE_PATH } = paths(true); - const { - appName, - bitbucketRepository, - bitbucketOwner, - bitbucketBranch, - bitbucketId, - serverId, - enableSubmodules, - } = 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"); - const repoclone = `bitbucket.org/${bitbucketOwner}/${bitbucketRepository}.git`; - const cloneUrl = getBitbucketCloneUrl(bitbucketProvider, repoclone); - - try { - const cloneCommand = ` - rm -rf ${outputPath}; - git clone --branch ${bitbucketBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} - `; - await execAsyncRemote(serverId, cloneCommand); - } catch (error) { - throw error; - } -}; - -export const getBitbucketCloneCommand = async ( - entity: ApplicationWithBitbucket | ComposeWithBitbucket, - logPath: string, - isCompose = false, -) => { - const { COMPOSE_PATH, APPLICATIONS_PATH } = paths(true); - const { - appName, - bitbucketRepository, - bitbucketOwner, - bitbucketBranch, - bitbucketId, - serverId, - enableSubmodules, - } = entity; - - if (!serverId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Server not found", - }); - } - - if (!bitbucketId) { - const command = ` - echo "Error: ❌ Bitbucket Provider not found" >> ${logPath}; - exit 1; - `; - await execAsyncRemote(serverId, command); - throw new TRPCError({ - code: "NOT_FOUND", - message: "Bitbucket Provider not found", - }); - } - - const bitbucketProvider = await findBitbucketById(bitbucketId); - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; - const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); - const repoclone = `bitbucket.org/${bitbucketOwner}/${bitbucketRepository}.git`; - const cloneUrl = getBitbucketCloneUrl(bitbucketProvider, repoclone); - - const cloneCommand = ` -rm -rf ${outputPath}; -mkdir -p ${outputPath}; -if ! git clone --branch ${bitbucketBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then - echo "❌ [ERROR] Fail to clone the repository ${repoclone}" >> ${logPath}; - exit 1; -fi -echo "Cloned ${repoclone} to ${outputPath}: ✅" >> ${logPath}; - `; - - return cloneCommand; + command += `echo "Cloning Repo ${repoclone} to ${outputPath}: ✅";`; + command += `git clone --branch ${bitbucketBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; + return command; }; export const getBitbucketRepositories = async (bitbucketId?: string) => { diff --git a/packages/server/src/utils/providers/git.ts b/packages/server/src/utils/providers/git.ts index 5779252db..19c8ab8a0 100644 --- a/packages/server/src/utils/providers/git.ts +++ b/packages/server/src/utils/providers/git.ts @@ -1,159 +1,64 @@ -import { createWriteStream } from "node:fs"; import path, { join } from "node:path"; import { paths } from "@dokploy/server/constants"; -import type { Compose } from "@dokploy/server/services/compose"; import { findSSHKeyById, updateSSHKeyById, } from "@dokploy/server/services/ssh-key"; -import { TRPCError } from "@trpc/server"; -import { recreateDirectory } from "../filesystem/directory"; -import { execAsync, execAsyncRemote } from "../process/execAsync"; -import { spawnAsync } from "../process/spawnAsync"; -export const cloneGitRepository = async ( - entity: { - appName: string; - customGitUrl?: string | null; - customGitBranch?: string | null; - customGitSSHKeyId?: string | null; - enableSubmodules?: boolean; - }, - logPath: string, - isCompose = false, -) => { - const { SSH_PATH, COMPOSE_PATH, APPLICATIONS_PATH } = paths(); +interface CloneGitRepository { + appName: string; + customGitUrl?: string | null; + customGitBranch?: string | null; + customGitSSHKeyId?: string | null; + enableSubmodules?: boolean; + serverId: string | null; + type?: "application" | "compose"; +} + +export const cloneGitRepository = async ({ + type = "application", + ...entity +}: CloneGitRepository) => { + let command = "set -e;"; const { appName, customGitUrl, customGitBranch, customGitSSHKeyId, enableSubmodules, + serverId, } = entity; + const { SSH_PATH, COMPOSE_PATH, APPLICATIONS_PATH } = paths(!!serverId); if (!customGitUrl || !customGitBranch) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error: Repository not found", - }); + command += `echo "Error: ❌ Repository not found"; exit 1;`; + return command; } - const writeStream = createWriteStream(logPath, { flags: "a" }); const temporalKeyPath = path.join("/tmp", "id_rsa"); if (customGitSSHKeyId) { const sshKey = await findSSHKeyById(customGitSSHKeyId); - await execAsync(` + command += ` echo "${sshKey.privateKey}" > ${temporalKeyPath} - chmod 600 ${temporalKeyPath} - `); + chmod 600 ${temporalKeyPath}; + `; } - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; + const basePath = type === "compose" ? COMPOSE_PATH : APPLICATIONS_PATH; const outputPath = join(basePath, appName, "code"); const knownHostsPath = path.join(SSH_PATH, "known_hosts"); - try { - if (!isHttpOrHttps(customGitUrl)) { - if (!customGitSSHKeyId) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: - "Error: you are trying to clone a ssh repository without a ssh key, please set a ssh key", - }); - } - await addHostToKnownHosts(customGitUrl); + if (!isHttpOrHttps(customGitUrl)) { + if (!customGitSSHKeyId) { + command += `echo "Error: ❌ You are trying to clone a ssh repository without a ssh key, please set a ssh key"; exit 1;`; + return command; } - await recreateDirectory(outputPath); - writeStream.write( - `\nCloning Repo Custom ${customGitUrl} to ${outputPath}: ✅\n`, - ); - - if (customGitSSHKeyId) { - await updateSSHKeyById({ - sshKeyId: customGitSSHKeyId, - lastUsedAt: new Date().toISOString(), - }); - } - - const { port } = sanitizeRepoPathSSH(customGitUrl); - const cloneArgs = [ - "clone", - "--branch", - customGitBranch, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - customGitUrl, - outputPath, - "--progress", - ]; - - await spawnAsync( - "git", - cloneArgs, - (data) => { - if (writeStream.writable) { - writeStream.write(data); - } - }, - { - env: { - ...process.env, - ...(customGitSSHKeyId && { - GIT_SSH_COMMAND: `ssh -i ${temporalKeyPath}${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`, - }), - }, - }, - ); - - writeStream.write(`\nCloned Custom Git ${customGitUrl}: ✅\n`); - } catch (error) { - writeStream.write(`\nERROR Cloning Custom Git: ${error}: ❌\n`); - throw error; - } finally { - writeStream.end(); + command += addHostToKnownHostsCommand(customGitUrl); } -}; - -export const getCustomGitCloneCommand = async ( - entity: { - appName: string; - customGitUrl?: string | null; - customGitBranch?: string | null; - customGitSSHKeyId?: string | null; - serverId: string | null; - enableSubmodules: boolean; - }, - logPath: string, - isCompose = false, -) => { - const { SSH_PATH, COMPOSE_PATH, APPLICATIONS_PATH } = paths(true); - const { - appName, - customGitUrl, - customGitBranch, - customGitSSHKeyId, - serverId, - enableSubmodules, - } = entity; - - if (!customGitUrl || !customGitBranch) { - const command = ` - echo "Error: ❌ Repository not found" >> ${logPath}; - exit 1; - `; - - await execAsyncRemote(serverId, command); - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error: Repository not found", - }); - } - - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; - const outputPath = join(basePath, appName, "code"); - const knownHostsPath = path.join(SSH_PATH, "known_hosts"); + command += `rm -rf ${outputPath};`; + command += `mkdir -p ${outputPath};`; + command += `echo "Cloning Repo Custom ${customGitUrl} to ${outputPath}: ✅";`; if (customGitSSHKeyId) { await updateSSHKeyById({ @@ -161,48 +66,22 @@ export const getCustomGitCloneCommand = async ( lastUsedAt: new Date().toISOString(), }); } - try { - const command = []; - if (!isHttpOrHttps(customGitUrl)) { - if (!customGitSSHKeyId) { - command.push( - `echo "Error: you are trying to clone a ssh repository without a ssh key, please set a ssh key ❌" >> ${logPath}; - exit 1; - `, - ); - } - command.push(addHostToKnownHostsCommand(customGitUrl)); - } - command.push(`rm -rf ${outputPath};`); - command.push(`mkdir -p ${outputPath};`); - command.push( - `echo "Cloning Custom Git ${customGitUrl}" to ${outputPath}: ✅ >> ${logPath};`, - ); - if (customGitSSHKeyId) { - const sshKey = await findSSHKeyById(customGitSSHKeyId); - const { port } = sanitizeRepoPathSSH(customGitUrl); - const gitSshCommand = `ssh -i /tmp/id_rsa${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`; - command.push( - ` - echo "${sshKey.privateKey}" > /tmp/id_rsa - chmod 600 /tmp/id_rsa - export GIT_SSH_COMMAND="${gitSshCommand}" - `, - ); - } - command.push( - `if ! git clone --branch ${customGitBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${customGitUrl} ${outputPath} >> ${logPath} 2>&1; then - echo "❌ [ERROR] Fail to clone the repository ${customGitUrl}" >> ${logPath}; + if (customGitSSHKeyId) { + const sshKey = await findSSHKeyById(customGitSSHKeyId); + const { port } = sanitizeRepoPathSSH(customGitUrl); + const gitSshCommand = `ssh -i /tmp/id_rsa${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`; + command += `echo "${sshKey.privateKey}" > /tmp/id_rsa;`; + command += "chmod 600 /tmp/id_rsa;"; + command += `export GIT_SSH_COMMAND="${gitSshCommand}";`; + } + command += `if ! git clone --branch ${customGitBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${customGitUrl} ${outputPath}; then + echo "❌ [ERROR] Fail to clone the repository ${customGitUrl}"; exit 1; fi - `, - ); - command.push(`echo "Cloned Custom Git ${customGitUrl}: ✅" >> ${logPath};`); - return command.join("\n"); - } catch (error) { - throw error; - } + `; + + return command; }; const isHttpOrHttps = (url: string): boolean => { @@ -210,19 +89,19 @@ const isHttpOrHttps = (url: string): boolean => { return regex.test(url); }; -const addHostToKnownHosts = async (repositoryURL: string) => { - const { SSH_PATH } = paths(); - const { domain, port } = sanitizeRepoPathSSH(repositoryURL); - const knownHostsPath = path.join(SSH_PATH, "known_hosts"); +// const addHostToKnownHosts = async (repositoryURL: string) => { +// const { SSH_PATH } = paths(); +// const { domain, port } = sanitizeRepoPathSSH(repositoryURL); +// const knownHostsPath = path.join(SSH_PATH, "known_hosts"); - const command = `ssh-keyscan -p ${port} ${domain} >> ${knownHostsPath}`; - try { - await execAsync(command); - } catch (error) { - console.error(`Error adding host to known_hosts: ${error}`); - throw error; - } -}; +// const command = `ssh-keyscan -p ${port} ${domain} >> ${knownHostsPath}`; +// try { +// await execAsync(command); +// } catch (error) { +// console.error(`Error adding host to known_hosts: ${error}`); +// throw error; +// } +// }; const addHostToKnownHostsCommand = (repositoryURL: string) => { const { SSH_PATH } = paths(true); @@ -266,161 +145,3 @@ const sanitizeRepoPathSSH = (input: string) => { }, }; }; - -export const cloneGitRawRepository = async (entity: { - appName: string; - customGitUrl?: string | null; - customGitBranch?: string | null; - customGitSSHKeyId?: string | null; - enableSubmodules?: boolean; -}) => { - const { - appName, - customGitUrl, - customGitBranch, - customGitSSHKeyId, - enableSubmodules, - } = entity; - - if (!customGitUrl || !customGitBranch) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error: Repository not found", - }); - } - - const { SSH_PATH, COMPOSE_PATH } = paths(); - const temporalKeyPath = path.join("/tmp", "id_rsa"); - const basePath = COMPOSE_PATH; - const outputPath = join(basePath, appName, "code"); - const knownHostsPath = path.join(SSH_PATH, "known_hosts"); - - if (customGitSSHKeyId) { - const sshKey = await findSSHKeyById(customGitSSHKeyId); - - await execAsync(` - echo "${sshKey.privateKey}" > ${temporalKeyPath} - chmod 600 ${temporalKeyPath} - `); - } - - try { - if (!isHttpOrHttps(customGitUrl)) { - if (!customGitSSHKeyId) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: - "Error: you are trying to clone a ssh repository without a ssh key, please set a ssh key", - }); - } - await addHostToKnownHosts(customGitUrl); - } - await recreateDirectory(outputPath); - - if (customGitSSHKeyId) { - await updateSSHKeyById({ - sshKeyId: customGitSSHKeyId, - lastUsedAt: new Date().toISOString(), - }); - } - - const { port } = sanitizeRepoPathSSH(customGitUrl); - const cloneArgs = [ - "clone", - "--branch", - customGitBranch, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - customGitUrl, - outputPath, - "--progress", - ]; - - await spawnAsync("git", cloneArgs, (_data) => {}, { - env: { - ...process.env, - ...(customGitSSHKeyId && { - GIT_SSH_COMMAND: `ssh -i ${temporalKeyPath}${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`, - }), - }, - }); - } catch (error) { - throw error; - } -}; - -export const cloneRawGitRepositoryRemote = async (compose: Compose) => { - const { - appName, - customGitBranch, - customGitUrl, - customGitSSHKeyId, - serverId, - enableSubmodules, - } = 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 { SSH_PATH, COMPOSE_PATH } = paths(true); - 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)) { - if (!customGitSSHKeyId) { - command.push( - `echo "Error: you are trying to clone a ssh repository without a ssh key, please set a ssh key ❌" ; - exit 1; - `, - ); - } - command.push(addHostToKnownHostsCommand(customGitUrl)); - } - command.push(`rm -rf ${outputPath};`); - command.push(`mkdir -p ${outputPath};`); - if (customGitSSHKeyId) { - const sshKey = await findSSHKeyById(customGitSSHKeyId); - const { port } = sanitizeRepoPathSSH(customGitUrl); - const gitSshCommand = `ssh -i /tmp/id_rsa${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`; - command.push( - ` - echo "${sshKey.privateKey}" > /tmp/id_rsa - chmod 600 /tmp/id_rsa - export GIT_SSH_COMMAND="${gitSshCommand}" - `, - ); - } - - command.push( - `if ! git clone --branch ${customGitBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --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/packages/server/src/utils/providers/gitea.ts b/packages/server/src/utils/providers/gitea.ts index db6dcbb78..5b69f6826 100644 --- a/packages/server/src/utils/providers/gitea.ts +++ b/packages/server/src/utils/providers/gitea.ts @@ -1,7 +1,5 @@ -import { createWriteStream } from "node:fs"; import { join } from "node:path"; import { paths } from "@dokploy/server/constants"; -import type { Compose } from "@dokploy/server/services/compose"; import { findGiteaById, type Gitea, @@ -9,9 +7,6 @@ import { } from "@dokploy/server/services/gitea"; import type { InferResultType } from "@dokploy/server/types/with"; import { TRPCError } from "@trpc/server"; -import { recreateDirectory } from "../filesystem/directory"; -import { execAsyncRemote } from "../process/execAsync"; -import { spawnAsync } from "../process/spawnAsync"; export const getErrorCloneRequirements = (entity: { giteaRepository?: string | null; @@ -119,79 +114,16 @@ export type ApplicationWithGitea = InferResultType< export type ComposeWithGitea = InferResultType<"compose", { gitea: true }>; -export const getGiteaCloneCommand = async ( - entity: ApplicationWithGitea | ComposeWithGitea, - logPath: string, - isCompose = false, -) => { - const { - appName, - giteaBranch, - giteaId, - giteaOwner, - giteaRepository, - serverId, - enableSubmodules, - } = entity; - - if (!serverId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Server not found", - }); - } - - if (!giteaId) { - const command = ` - echo "Error: ❌ Gitlab Provider not found" >> ${logPath}; - exit 1; - `; - - await execAsyncRemote(serverId, command); - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitea Provider not found", - }); - } - - // Use paths(true) for remote operations - const { COMPOSE_PATH, APPLICATIONS_PATH } = paths(true); - await refreshGiteaToken(giteaId); - const gitea = await findGiteaById(giteaId); - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; - const outputPath = join(basePath, appName, "code"); - - const repoClone = `${giteaOwner}/${giteaRepository}.git`; - const cloneUrl = buildGiteaCloneUrl( - gitea?.giteaUrl!, - gitea?.accessToken!, - giteaOwner!, - giteaRepository!, - ); - - const cloneCommand = ` - rm -rf ${outputPath}; - mkdir -p ${outputPath}; - - if ! git clone --branch ${giteaBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then - echo "❌ [ERROR] Failed to clone the repository ${repoClone}" >> ${logPath}; - exit 1; - fi - - echo "Cloned ${repoClone} to ${outputPath}: ✅" >> ${logPath}; - `; - - return cloneCommand; +type GiteaClone = (ApplicationWithGitea | ComposeWithGitea) & { + serverId: string | null; + type?: "application" | "compose"; }; -export const cloneGiteaRepository = async ( - entity: ApplicationWithGitea | ComposeWithGitea, - logPath: string, - isCompose = false, -) => { - const { APPLICATIONS_PATH, COMPOSE_PATH } = paths(); - - const writeStream = createWriteStream(logPath, { flags: "a" }); +export const cloneGiteaRepository = async ({ + type = "application", + ...entity +}: GiteaClone) => { + let command = "set -e;"; const { appName, giteaBranch, @@ -199,27 +131,27 @@ export const cloneGiteaRepository = async ( giteaOwner, giteaRepository, enableSubmodules, + serverId, } = entity; + const { APPLICATIONS_PATH, COMPOSE_PATH } = paths(!!serverId); if (!giteaId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitea Provider not found", - }); + command += `echo "Error: ❌ Gitea Provider not found"; exit 1;`; + return command; } await refreshGiteaToken(giteaId); const giteaProvider = await findGiteaById(giteaId); + if (!giteaProvider) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitea provider not found in the database", - }); + command += `echo "❌ [ERROR] Gitea provider not found in the database"; exit 1;`; + return command; } - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; + const basePath = type === "compose" ? COMPOSE_PATH : APPLICATIONS_PATH; const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); + command += `rm -rf ${outputPath};`; + command += `mkdir -p ${outputPath};`; const repoClone = `${giteaOwner}/${giteaRepository}.git`; const cloneUrl = buildGiteaCloneUrl( @@ -229,134 +161,9 @@ export const cloneGiteaRepository = async ( giteaRepository!, ); - writeStream.write(`\nCloning Repo ${repoClone} to ${outputPath}...\n`); - - try { - await spawnAsync( - "git", - [ - "clone", - "--branch", - giteaBranch!, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - cloneUrl, - outputPath, - "--progress", - ], - (data) => { - if (writeStream.writable) { - writeStream.write(data); - } - }, - ); - writeStream.write(`\nCloned ${repoClone}: ✅\n`); - } catch (error) { - writeStream.write(`ERROR Cloning: ${error}: ❌`); - throw error; - } finally { - writeStream.end(); - } -}; - -export const cloneRawGiteaRepository = async (entity: Compose) => { - const { - appName, - giteaRepository, - giteaOwner, - giteaBranch, - giteaId, - enableSubmodules, - } = entity; - const { COMPOSE_PATH } = paths(); - - if (!giteaId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitea Provider not found", - }); - } - await refreshGiteaToken(giteaId); - const giteaProvider = await findGiteaById(giteaId); - if (!giteaProvider) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitea provider not found in the database", - }); - } - - const basePath = COMPOSE_PATH; - const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); - - const cloneUrl = buildGiteaCloneUrl( - giteaProvider.giteaUrl, - giteaProvider.accessToken!, - giteaOwner!, - giteaRepository!, - ); - - try { - await spawnAsync("git", [ - "clone", - "--branch", - giteaBranch!, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - cloneUrl, - outputPath, - "--progress", - ]); - } catch (error) { - throw error; - } -}; - -export const cloneRawGiteaRepositoryRemote = async (compose: Compose) => { - const { - appName, - giteaRepository, - giteaOwner, - giteaBranch, - giteaId, - serverId, - enableSubmodules, - } = compose; - - if (!serverId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Server not found", - }); - } - if (!giteaId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitea Provider not found", - }); - } - const { COMPOSE_PATH } = paths(true); - const giteaProvider = await findGiteaById(giteaId); - const basePath = COMPOSE_PATH; - const outputPath = join(basePath, appName, "code"); - const cloneUrl = buildGiteaCloneUrl( - giteaProvider.giteaUrl, - giteaProvider.accessToken!, - giteaOwner!, - giteaRepository!, - ); - - try { - const command = ` - rm -rf ${outputPath}; - git clone --branch ${giteaBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} - `; - await execAsyncRemote(serverId, command); - } catch (error) { - throw error; - } + command += `echo "Cloning Repo ${repoClone} to ${outputPath}: ✅";`; + command += `git clone --branch ${giteaBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; + return command; }; export const haveGiteaRequirements = (giteaProvider: Gitea) => { diff --git a/packages/server/src/utils/providers/github.ts b/packages/server/src/utils/providers/github.ts index 30125db8b..c0f1b651a 100644 --- a/packages/server/src/utils/providers/github.ts +++ b/packages/server/src/utils/providers/github.ts @@ -1,16 +1,11 @@ -import { createWriteStream } from "node:fs"; import { join } from "node:path"; import { paths } from "@dokploy/server/constants"; import type { apiFindGithubBranches } from "@dokploy/server/db/schema"; -import type { Compose } from "@dokploy/server/services/compose"; import { findGithubById, type Github } from "@dokploy/server/services/github"; import type { InferResultType } from "@dokploy/server/types/with"; import { createAppAuth } from "@octokit/auth-app"; import { TRPCError } from "@trpc/server"; import { Octokit } from "octokit"; -import { recreateDirectory } from "../filesystem/directory"; -import { execAsyncRemote } from "../process/execAsync"; -import { spawnAsync } from "../process/spawnAsync"; export const authGithub = (githubProvider: Github): Octokit => { if (!haveGithubRequirements(githubProvider)) { @@ -123,42 +118,39 @@ interface CloneGithubRepository { branch: string | null; githubId: string | null; repository: string | null; - logPath: string; type?: "application" | "compose"; enableSubmodules: boolean; + serverId: string | null; } export const cloneGithubRepository = async ({ - logPath, type = "application", ...entity }: CloneGithubRepository) => { + let command = "set -e;"; const isCompose = type === "compose"; - const { APPLICATIONS_PATH, COMPOSE_PATH } = paths(); - const writeStream = createWriteStream(logPath, { flags: "a" }); - const { appName, repository, owner, branch, githubId, enableSubmodules } = - entity; + const { + appName, + repository, + owner, + branch, + githubId, + enableSubmodules, + serverId, + } = entity; + const { APPLICATIONS_PATH, COMPOSE_PATH } = paths(!!serverId); if (!githubId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "GitHub Provider not found", - }); + command += `echo "Error: ❌ Github Provider not found"; exit 1;`; + + return command; } const requirements = getErrorCloneRequirements(entity); // Check if requirements are met if (requirements.length > 0) { - writeStream.write( - `\nGitHub Repository configuration failed for application: ${appName}\n`, - ); - writeStream.write("Reasons:\n"); - writeStream.write(requirements.join("\n")); - writeStream.end(); - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error: GitHub repository information is incomplete.", - }); + command += `echo "GitHub Repository configuration failed for application: ${appName}"; echo "Reasons:"; echo "${requirements.join("\n")}"; exit 1;`; + return command; } const githubProvider = await findGithubById(githubId); @@ -167,193 +159,15 @@ export const cloneGithubRepository = async ({ const octokit = authGithub(githubProvider); const token = await getGithubToken(octokit); const repoclone = `github.com/${owner}/${repository}.git`; - await recreateDirectory(outputPath); + // await recreateDirectory(outputPath); + command += `rm -rf ${outputPath};`; + command += `mkdir -p ${outputPath};`; const cloneUrl = `https://oauth2:${token}@${repoclone}`; - try { - writeStream.write(`\nCloning Repo ${repoclone} to ${outputPath}: ✅\n`); - const cloneArgs = [ - "clone", - "--branch", - branch!, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - cloneUrl, - outputPath, - "--progress", - ]; + command += `echo "Cloning Repo ${repoclone} to ${outputPath}: ✅";`; + command += `git clone --branch ${branch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; - await spawnAsync("git", cloneArgs, (data) => { - if (writeStream.writable) { - writeStream.write(data); - } - }); - writeStream.write(`\nCloned ${repoclone}: ✅\n`); - } catch (error) { - writeStream.write(`ERROR Cloning: ${error}: ❌`); - throw error; - } finally { - writeStream.end(); - } -}; - -export const getGithubCloneCommand = async ({ - logPath, - type = "application", - ...entity -}: CloneGithubRepository & { serverId: string }) => { - const { - appName, - repository, - owner, - branch, - githubId, - serverId, - enableSubmodules, - } = entity; - const isCompose = type === "compose"; - if (!serverId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Server not found", - }); - } - - if (!githubId) { - const command = ` - echo "Error: ❌ Github Provider not found" >> ${logPath}; - exit 1; - `; - - await execAsyncRemote(serverId, command); - throw new TRPCError({ - code: "NOT_FOUND", - message: "GitHub Provider not found", - }); - } - - const requirements = getErrorCloneRequirements(entity); - - // Build log messages - let logMessages = ""; - if (requirements.length > 0) { - logMessages += `\nGitHub Repository configuration failed for application: ${appName}\n`; - logMessages += "Reasons:\n"; - logMessages += requirements.join("\n"); - const escapedLogMessages = logMessages - .replace(/\\/g, "\\\\") - .replace(/"/g, '\\"') - .replace(/\n/g, "\\n"); - - const bashCommand = ` - echo "${escapedLogMessages}" >> ${logPath}; - exit 1; # Exit with error code - `; - - await execAsyncRemote(serverId, bashCommand); - return; - } - const { COMPOSE_PATH, APPLICATIONS_PATH } = paths(true); - const githubProvider = await findGithubById(githubId); - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; - const outputPath = join(basePath, appName, "code"); - const octokit = authGithub(githubProvider); - const token = await getGithubToken(octokit); - const repoclone = `github.com/${owner}/${repository}.git`; - const cloneUrl = `https://oauth2:${token}@${repoclone}`; - - const cloneCommand = ` -rm -rf ${outputPath}; -mkdir -p ${outputPath}; -if ! git clone --branch ${branch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then - echo "❌ [ERROR] Fail to clone repository ${repoclone}" >> ${logPath}; - exit 1; -fi -echo "Cloned ${repoclone} to ${outputPath}: ✅" >> ${logPath}; - `; - - return cloneCommand; -}; - -export const cloneRawGithubRepository = async (entity: Compose) => { - const { appName, repository, owner, branch, githubId, enableSubmodules } = - entity; - - if (!githubId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "GitHub Provider not found", - }); - } - const { COMPOSE_PATH } = paths(); - 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 { - const cloneArgs = [ - "clone", - "--branch", - branch!, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - cloneUrl, - outputPath, - "--progress", - ]; - await spawnAsync("git", cloneArgs); - } catch (error) { - throw error; - } -}; - -export const cloneRawGithubRepositoryRemote = async (compose: Compose) => { - const { - appName, - repository, - owner, - branch, - githubId, - serverId, - enableSubmodules, - } = 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 { COMPOSE_PATH } = paths(true); - 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`; - const cloneUrl = `https://oauth2:${token}@${repoclone}`; - try { - const command = ` - rm -rf ${outputPath}; - git clone --branch ${branch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} - `; - await execAsyncRemote(serverId, command); - } catch (error) { - throw error; - } + return command; }; export const getGithubRepositories = async (githubId?: string) => { diff --git a/packages/server/src/utils/providers/gitlab.ts b/packages/server/src/utils/providers/gitlab.ts index 840347fdb..9c75cd239 100644 --- a/packages/server/src/utils/providers/gitlab.ts +++ b/packages/server/src/utils/providers/gitlab.ts @@ -1,8 +1,6 @@ -import { createWriteStream } from "node:fs"; import { join } from "node:path"; import { paths } from "@dokploy/server/constants"; import type { apiGitlabTestConnection } from "@dokploy/server/db/schema"; -import type { Compose } from "@dokploy/server/services/compose"; import { findGitlabById, type Gitlab, @@ -10,9 +8,6 @@ import { } from "@dokploy/server/services/gitlab"; import type { InferResultType } from "@dokploy/server/types/with"; import { TRPCError } from "@trpc/server"; -import { recreateDirectory } from "../filesystem/directory"; -import { execAsyncRemote } from "../process/execAsync"; -import { spawnAsync } from "../process/spawnAsync"; export const refreshGitlabToken = async (gitlabProviderId: string) => { const gitlabProvider = await findGitlabById(gitlabProviderId); @@ -102,25 +97,29 @@ const getGitlabCloneUrl = (gitlab: GitlabInfo, repoClone: string) => { return cloneUrl; }; -export const cloneGitlabRepository = async ( - entity: ApplicationWithGitlab | ComposeWithGitlab, - logPath: string, - isCompose = false, -) => { - const writeStream = createWriteStream(logPath, { flags: "a" }); +type GitlabClone = (ApplicationWithGitlab | ComposeWithGitlab) & { + serverId: string | null; + type?: "application" | "compose"; +}; + +export const cloneGitlabRepository = async ({ + type = "application", + ...entity +}: GitlabClone) => { + let command = "set -e;"; const { appName, gitlabBranch, gitlabId, gitlabPathNamespace, enableSubmodules, + serverId, } = entity; + const { COMPOSE_PATH, APPLICATIONS_PATH } = paths(!!serverId); if (!gitlabId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitlab Provider not found", - }); + command += `echo "Error: ❌ Gitlab Provider not found"; exit 1;`; + return command; } await refreshGitlabToken(gitlabId); @@ -130,127 +129,19 @@ export const cloneGitlabRepository = async ( // Check if requirements are met if (requirements.length > 0) { - writeStream.write( - `\nGitLab Repository configuration failed for application: ${appName}\n`, - ); - writeStream.write("Reasons:\n"); - writeStream.write(requirements.join("\n")); - writeStream.end(); - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error: GitLab repository information is incomplete.", - }); + command += `echo "❌ [ERROR] GitLab Repository configuration failed for application: ${appName}"; echo "Reasons:"; echo "${requirements.join("\n")}"; exit 1;`; + return command; } - const { COMPOSE_PATH, APPLICATIONS_PATH } = paths(); - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; + const basePath = type === "compose" ? COMPOSE_PATH : APPLICATIONS_PATH; const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); + command += `rm -rf ${outputPath};`; + command += `mkdir -p ${outputPath};`; const repoClone = getGitlabRepoClone(gitlab, gitlabPathNamespace); const cloneUrl = getGitlabCloneUrl(gitlab, repoClone); - try { - writeStream.write(`\nCloning Repo ${repoClone} to ${outputPath}: ✅\n`); - const cloneArgs = [ - "clone", - "--branch", - gitlabBranch!, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - cloneUrl, - outputPath, - "--progress", - ]; - - await spawnAsync("git", cloneArgs, (data) => { - if (writeStream.writable) { - writeStream.write(data); - } - }); - writeStream.write(`\nCloned ${repoClone}: ✅\n`); - } catch (error) { - writeStream.write(`ERROR Cloning: ${error}: ❌`); - throw error; - } finally { - writeStream.end(); - } -}; - -export const getGitlabCloneCommand = async ( - entity: ApplicationWithGitlab | ComposeWithGitlab, - logPath: string, - isCompose = false, -) => { - const { - appName, - gitlabPathNamespace, - gitlabBranch, - gitlabId, - serverId, - enableSubmodules, - } = entity; - - if (!serverId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Server not found", - }); - } - - if (!gitlabId) { - const command = ` - echo "Error: ❌ Gitlab Provider not found" >> ${logPath}; - exit 1; - `; - - await execAsyncRemote(serverId, command); - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitlab Provider not found", - }); - } - - const requirements = getErrorCloneRequirements(entity); - - // Build log messages - let logMessages = ""; - if (requirements.length > 0) { - logMessages += `\nGitLab Repository configuration failed for application: ${appName}\n`; - logMessages += "Reasons:\n"; - logMessages += requirements.join("\n"); - const escapedLogMessages = logMessages - .replace(/\\/g, "\\\\") - .replace(/"/g, '\\"') - .replace(/\n/g, "\\n"); - - const bashCommand = ` - echo "${escapedLogMessages}" >> ${logPath}; - exit 1; # Exit with error code - `; - - await execAsyncRemote(serverId, bashCommand); - return; - } - - const { COMPOSE_PATH, APPLICATIONS_PATH } = paths(true); - await refreshGitlabToken(gitlabId); - const gitlab = await findGitlabById(gitlabId); - const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH; - const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); - const repoClone = getGitlabRepoClone(gitlab, gitlabPathNamespace); - const cloneUrl = getGitlabCloneUrl(gitlab, repoClone); - const cloneCommand = ` -rm -rf ${outputPath}; -mkdir -p ${outputPath}; -if ! git clone --branch ${gitlabBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then - echo "❌ [ERROR] Fail to clone the repository ${repoClone}" >> ${logPath}; - exit 1; -fi -echo "Cloned ${repoClone} to ${outputPath}: ✅" >> ${logPath}; - `; - - return cloneCommand; + command += `echo "Cloning Repo ${repoClone} to ${outputPath}: ✅";`; + command += `git clone --branch ${gitlabBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} --progress;`; + return command; }; export const getGitlabRepositories = async (gitlabId?: string) => { @@ -355,88 +246,6 @@ export const getGitlabBranches = async (input: { }[]; }; -export const cloneRawGitlabRepository = async (entity: Compose) => { - const { - appName, - gitlabBranch, - gitlabId, - gitlabPathNamespace, - enableSubmodules, - } = entity; - - if (!gitlabId) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "Gitlab Provider not found", - }); - } - - const { COMPOSE_PATH } = paths(); - await refreshGitlabToken(gitlabId); - const gitlabProvider = await findGitlabById(gitlabId); - const basePath = COMPOSE_PATH; - const outputPath = join(basePath, appName, "code"); - await recreateDirectory(outputPath); - const repoClone = getGitlabRepoClone(gitlabProvider, gitlabPathNamespace); - const cloneUrl = getGitlabCloneUrl(gitlabProvider, repoClone); - try { - const cloneArgs = [ - "clone", - "--branch", - gitlabBranch!, - "--depth", - "1", - ...(enableSubmodules ? ["--recurse-submodules"] : []), - cloneUrl, - outputPath, - "--progress", - ]; - await spawnAsync("git", cloneArgs); - } catch (error) { - throw error; - } -}; - -export const cloneRawGitlabRepositoryRemote = async (compose: Compose) => { - const { - appName, - gitlabPathNamespace, - gitlabBranch, - gitlabId, - serverId, - enableSubmodules, - } = 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 { COMPOSE_PATH } = paths(true); - await refreshGitlabToken(gitlabId); - const gitlabProvider = await findGitlabById(gitlabId); - const basePath = COMPOSE_PATH; - const outputPath = join(basePath, appName, "code"); - const repoClone = getGitlabRepoClone(gitlabProvider, gitlabPathNamespace); - const cloneUrl = getGitlabCloneUrl(gitlabProvider, repoClone); - try { - const command = ` - rm -rf ${outputPath}; - git clone --branch ${gitlabBranch} --depth 1 ${enableSubmodules ? "--recurse-submodules" : ""} ${cloneUrl} ${outputPath} - `; - await execAsyncRemote(serverId, command); - } catch (error) { - throw error; - } -}; - export const testGitlabConnection = async ( input: typeof apiGitlabTestConnection._type, ) => { diff --git a/packages/server/src/utils/providers/raw.ts b/packages/server/src/utils/providers/raw.ts index 34ba0012a..7b541867d 100644 --- a/packages/server/src/utils/providers/raw.ts +++ b/packages/server/src/utils/providers/raw.ts @@ -1,4 +1,3 @@ -import { createWriteStream } from "node:fs"; import { writeFile } from "node:fs/promises"; import { join } from "node:path"; import { paths } from "@dokploy/server/constants"; @@ -7,33 +6,7 @@ import { encodeBase64 } from "../docker/utils"; import { recreateDirectory } from "../filesystem/directory"; import { execAsyncRemote } from "../process/execAsync"; -export const createComposeFile = async (compose: Compose, logPath: string) => { - const { COMPOSE_PATH } = paths(); - const { appName, composeFile } = compose; - const writeStream = createWriteStream(logPath, { flags: "a" }); - const outputPath = join(COMPOSE_PATH, appName, "code"); - - try { - await recreateDirectory(outputPath); - writeStream.write( - `\nCreating File 'docker-compose.yml' to ${outputPath}: ✅\n`, - ); - - await writeFile(join(outputPath, "docker-compose.yml"), composeFile); - - writeStream.write(`\nFile 'docker-compose.yml' created: ✅\n`); - } catch (error) { - writeStream.write(`\nERROR Creating Compose File: ${error}: ❌\n`); - throw error; - } finally { - writeStream.end(); - } -}; - -export const getCreateComposeFileCommand = ( - compose: Compose, - logPath: string, -) => { +export const getCreateComposeFileCommand = (compose: Compose) => { const { COMPOSE_PATH } = paths(true); const { appName, composeFile } = compose; const outputPath = join(COMPOSE_PATH, appName, "code"); @@ -43,7 +16,7 @@ export const getCreateComposeFileCommand = ( rm -rf ${outputPath}; mkdir -p ${outputPath}; echo "${encodedContent}" | base64 -d > "${filePath}"; - echo "File 'docker-compose.yml' created: ✅" >> ${logPath}; + echo "File 'docker-compose.yml' created: ✅"; `; return bashCommand; };