refactor(deployments): improve build error

This commit is contained in:
Mauricio Siu
2024-09-15 14:48:40 -06:00
parent d2c8632c4f
commit 0d3c978aad
16 changed files with 464 additions and 178 deletions

View File

@@ -189,12 +189,14 @@ export const applicationRouter = createTRPCRouter({
redeploy: protectedProcedure redeploy: protectedProcedure
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
const application = await findApplicationById(input.applicationId);
const jobData: DeploymentJob = { const jobData: DeploymentJob = {
applicationId: input.applicationId, applicationId: input.applicationId,
titleLog: "Rebuild deployment", titleLog: "Rebuild deployment",
descriptionLog: "", descriptionLog: "",
type: "redeploy", type: "redeploy",
applicationType: "application", applicationType: "application",
server: !!application.serverId,
}; };
await myQueue.add( await myQueue.add(
"deployments", "deployments",
@@ -334,13 +336,14 @@ export const applicationRouter = createTRPCRouter({
deploy: protectedProcedure deploy: protectedProcedure
.input(apiFindOneApplication) .input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
// const application = await findApplicationById(input.applicationId); const application = await findApplicationById(input.applicationId);
const jobData: DeploymentJob = { const jobData: DeploymentJob = {
applicationId: input.applicationId, applicationId: input.applicationId,
titleLog: "Manual deployment", titleLog: "Manual deployment",
descriptionLog: "", descriptionLog: "",
type: "deploy", type: "deploy",
applicationType: "application", applicationType: "application",
server: !!application.serverId,
}; };
await myQueue.add( await myQueue.add(
"deployments", "deployments",
@@ -350,10 +353,6 @@ export const applicationRouter = createTRPCRouter({
removeOnFail: true, removeOnFail: true,
}, },
); );
// if (!application.serverId) {
// } else {
// await enqueueDeploymentJob(application.serverId, jobData);
// }
}), }),
cleanQueues: protectedProcedure cleanQueues: protectedProcedure

View File

@@ -169,14 +169,6 @@ export const composeRouter = createTRPCRouter({
deploy: protectedProcedure deploy: protectedProcedure
.input(apiFindCompose) .input(apiFindCompose)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
// const jobData: DeploymentJob = {
// composeId: input.composeId,
// titleLog: "Manual deployment",
// type: "deploy",
// applicationType: "compose",
// descriptionLog: "",
// };
const compose = await findComposeById(input.composeId); const compose = await findComposeById(input.composeId);
const jobData: DeploymentJob = { const jobData: DeploymentJob = {
composeId: input.composeId, composeId: input.composeId,
@@ -184,6 +176,7 @@ export const composeRouter = createTRPCRouter({
type: "deploy", type: "deploy",
applicationType: "compose", applicationType: "compose",
descriptionLog: "", descriptionLog: "",
server: !!compose.serverId,
}; };
await myQueue.add( await myQueue.add(
"deployments", "deployments",
@@ -193,10 +186,6 @@ export const composeRouter = createTRPCRouter({
removeOnFail: true, removeOnFail: true,
}, },
); );
// if (!compose.serverId) {
// } else {
// await enqueueDeploymentJob(compose.serverId, jobData);
// }
}), }),
redeploy: protectedProcedure redeploy: protectedProcedure
.input(apiFindCompose) .input(apiFindCompose)

View File

@@ -261,18 +261,6 @@ export const rebuildApplication = async ({
}); });
try { try {
if (application.serverId) {
let command = "set -e;";
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);
} else {
if (application.sourceType === "github") { if (application.sourceType === "github") {
await buildApplication(application, deployment.logPath); await buildApplication(application, deployment.logPath);
} else if (application.sourceType === "gitlab") { } else if (application.sourceType === "gitlab") {
@@ -286,6 +274,121 @@ export const rebuildApplication = async ({
} else if (application.sourceType === "drop") { } else if (application.sourceType === "drop") {
await buildApplication(application, deployment.logPath); 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.projectId}/services/application/${application.applicationId}?tab=deployments`;
const deployment = await createDeployment({
applicationId: applicationId,
title: titleLog,
description: descriptionLog,
});
try {
if (application.serverId) {
let command = "set -e;";
if (application.sourceType === "github") {
command += await getGithubCloneCommand(application, 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 === "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 updateDeploymentStatus(deployment.deploymentId, "done");
await updateApplicationStatus(applicationId, "done");
await sendBuildSuccessNotifications({
projectName: application.project.name,
applicationName: application.name,
applicationType: "application",
buildLink,
});
} catch (error) {
await updateDeploymentStatus(deployment.deploymentId, "error");
await updateApplicationStatus(applicationId, "error");
await sendBuildErrorNotifications({
projectName: application.project.name,
applicationName: application.name,
applicationType: "application",
// @ts-ignore
errorMessage: error?.message || "Error to build",
buildLink,
});
console.log(
"Error on ",
application.buildType,
"/",
application.sourceType,
error,
);
throw error;
}
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 updateDeploymentStatus(deployment.deploymentId, "done");
await updateApplicationStatus(applicationId, "done"); await updateApplicationStatus(applicationId, "done");

View File

@@ -210,49 +210,6 @@ export const deployCompose = async ({
}); });
try { try {
if (compose.serverId) {
let command = `
set -e;
`;
if (compose.sourceType === "github") {
command += await getGithubCloneCommand(
compose,
deployment.logPath,
true,
);
} 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,
);
} else if (compose.sourceType === "raw") {
command += getCreateComposeFileCommand(compose);
}
async function* sequentialSteps() {
yield execAsyncRemote(compose.serverId, command);
yield getBuildComposeCommand(compose, deployment.logPath);
}
const steps = sequentialSteps();
for await (const step of steps) {
step;
}
console.log(" ---- done ----");
} else {
if (compose.sourceType === "github") { if (compose.sourceType === "github") {
await cloneGithubRepository(compose, deployment.logPath, true); await cloneGithubRepository(compose, deployment.logPath, true);
} else if (compose.sourceType === "gitlab") { } else if (compose.sourceType === "gitlab") {
@@ -264,10 +221,7 @@ export const deployCompose = async ({
} else if (compose.sourceType === "raw") { } else if (compose.sourceType === "raw") {
await createComposeFile(compose, deployment.logPath); await createComposeFile(compose, deployment.logPath);
} }
await buildCompose(compose, deployment.logPath); await buildCompose(compose, deployment.logPath);
}
await updateDeploymentStatus(deployment.deploymentId, "done"); await updateDeploymentStatus(deployment.deploymentId, "done");
await updateCompose(composeId, { await updateCompose(composeId, {
composeStatus: "done", composeStatus: "done",
@@ -334,6 +288,132 @@ export const rebuildCompose = async ({
return true; 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.projectId}/services/compose/${compose.composeId}?tab=deployments`;
const deployment = await createDeploymentCompose({
composeId: composeId,
title: titleLog,
description: descriptionLog,
});
try {
if (compose.serverId) {
let command = "set -e;";
if (compose.sourceType === "github") {
command += await getGithubCloneCommand(
compose,
deployment.logPath,
true,
);
} 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,
);
} else if (compose.sourceType === "raw") {
command += getCreateComposeFileCommand(compose, deployment.logPath);
}
async function* sequentialSteps() {
yield execAsyncRemote(compose.serverId, command);
yield getBuildComposeCommand(compose, deployment.logPath);
}
const steps = sequentialSteps();
for await (const step of steps) {
step;
}
console.log(" ---- done ----");
}
await updateDeploymentStatus(deployment.deploymentId, "done");
await updateCompose(composeId, {
composeStatus: "done",
});
await sendBuildSuccessNotifications({
projectName: compose.project.name,
applicationName: compose.name,
applicationType: "compose",
buildLink,
});
} catch (error) {
await updateDeploymentStatus(deployment.deploymentId, "error");
await updateCompose(composeId, {
composeStatus: "error",
});
await sendBuildErrorNotifications({
projectName: compose.project.name,
applicationName: compose.name,
applicationType: "compose",
// @ts-ignore
errorMessage: error?.message || "Error to build",
buildLink,
});
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.serverId) {
await getBuildComposeCommand(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 removeCompose = async (compose: Compose) => { export const removeCompose = async (compose: Compose) => {
try { try {
const projectPath = join(COMPOSE_PATH, compose.appName); const projectPath = join(COMPOSE_PATH, compose.appName);

View File

@@ -1,12 +1,16 @@
import { type Job, Worker } from "bullmq"; import { type Job, Worker } from "bullmq";
import { import {
deployApplication, deployApplication,
deployRemoteApplication,
rebuildApplication, rebuildApplication,
rebuildRemoteApplication,
updateApplicationStatus, updateApplicationStatus,
} from "../api/services/application"; } from "../api/services/application";
import { import {
deployCompose, deployCompose,
deployRemoteCompose,
rebuildCompose, rebuildCompose,
rebuildRemoteCompose,
updateCompose, updateCompose,
} from "../api/services/compose"; } from "../api/services/compose";
import { myQueue, redisConfig } from "./queueSetup"; import { myQueue, redisConfig } from "./queueSetup";
@@ -16,6 +20,7 @@ type DeployJob =
applicationId: string; applicationId: string;
titleLog: string; titleLog: string;
descriptionLog: string; descriptionLog: string;
server?: boolean;
type: "deploy" | "redeploy"; type: "deploy" | "redeploy";
applicationType: "application"; applicationType: "application";
} }
@@ -23,6 +28,7 @@ type DeployJob =
composeId: string; composeId: string;
titleLog: string; titleLog: string;
descriptionLog: string; descriptionLog: string;
server?: boolean;
type: "deploy" | "redeploy"; type: "deploy" | "redeploy";
applicationType: "compose"; applicationType: "compose";
}; };
@@ -35,6 +41,21 @@ export const deploymentWorker = new Worker(
try { try {
if (job.data.applicationType === "application") { if (job.data.applicationType === "application") {
await updateApplicationStatus(job.data.applicationId, "running"); 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") { if (job.data.type === "redeploy") {
await rebuildApplication({ await rebuildApplication({
applicationId: job.data.applicationId, applicationId: job.data.applicationId,
@@ -48,10 +69,27 @@ export const deploymentWorker = new Worker(
descriptionLog: job.data.descriptionLog, descriptionLog: job.data.descriptionLog,
}); });
} }
}
} else if (job.data.applicationType === "compose") { } else if (job.data.applicationType === "compose") {
await updateCompose(job.data.composeId, { await updateCompose(job.data.composeId, {
composeStatus: "running", 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") { if (job.data.type === "deploy") {
await deployCompose({ await deployCompose({
composeId: job.data.composeId, composeId: job.data.composeId,
@@ -66,6 +104,7 @@ export const deploymentWorker = new Worker(
}); });
} }
} }
}
} catch (error) { } catch (error) {
console.log("Error", error); console.log("Error", error);
} }

View File

@@ -9,6 +9,7 @@ import { COMPOSE_PATH } from "@/server/constants";
import type { InferResultType } from "@/server/types/with"; import type { InferResultType } from "@/server/types/with";
import boxen from "boxen"; import boxen from "boxen";
import { import {
getComposePath,
writeDomainsToCompose, writeDomainsToCompose,
writeDomainsToComposeRemote, writeDomainsToComposeRemote,
} from "../docker/domain"; } from "../docker/domain";
@@ -73,12 +74,17 @@ export const getBuildComposeCommand = async (
compose: ComposeNested, compose: ComposeNested,
logPath: string, logPath: string,
) => { ) => {
const { sourceType, appName, mounts, composeType, domains } = compose; const { sourceType, appName, mounts, composeType, domains, composePath } =
compose;
const command = createCommand(compose); const command = createCommand(compose);
const envCommand = getCreateEnvFileCommand(compose); const envCommand = getCreateEnvFileCommand(compose);
const projectPath = join(COMPOSE_PATH, compose.appName, "code"); const projectPath = join(COMPOSE_PATH, compose.appName, "code");
const newCompose = await writeDomainsToComposeRemote(compose, domains); const newCompose = await writeDomainsToComposeRemote(
compose,
domains,
logPath,
);
const logContent = ` const logContent = `
App Name: ${appName} App Name: ${appName}
Build Compose 🐳 Build Compose 🐳
@@ -108,6 +114,11 @@ Compose Type: ${composeType} ✅`;
cd "${projectPath}"; cd "${projectPath}";
if [ ! -f "${composePath}" ]; then
echo "❌ Error: Compose file not found" >> "${logPath}";
exit 1;
fi
docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; } docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; }
echo "Docker Compose Deployed: ✅" >> "${logPath}" echo "Docker Compose Deployed: ✅" >> "${logPath}"

View File

@@ -6,7 +6,7 @@ import {
getDockerContextPath, getDockerContextPath,
} from "../filesystem/directory"; } from "../filesystem/directory";
import { spawnAsync } from "../process/spawnAsync"; import { spawnAsync } from "../process/spawnAsync";
import { createEnvFile } from "./utils"; import { createEnvFile, createEnvFileCommand } from "./utils";
export const buildCustomDocker = async ( export const buildCustomDocker = async (
application: ApplicationNested, application: ApplicationNested,
@@ -86,11 +86,27 @@ export const getDockerCommand = (
commandArgs.push("--build-arg", arg); commandArgs.push("--build-arg", arg);
} }
const command = ` /*
Do not generate an environment file when publishDirectory is specified,
as it could be publicly exposed.
*/
let command = "";
if (!publishDirectory) {
command += createEnvFileCommand(dockerFilePath, env);
}
command = `
echo "Building ${appName}" >> ${logPath}; echo "Building ${appName}" >> ${logPath};
cd ${dockerContextPath} || exit 1; cd ${dockerContextPath} >> ${logPath} 2>> ${logPath} || {
docker ${commandArgs.join(" ")} >> ${logPath} 2>&1; echo "❌ The path ${dockerContextPath} does not exist" >> ${logPath};
echo "Docker build completed." >> ${logPath}; exit 1;
}
docker ${commandArgs.join(" ")} >> ${logPath} 2>> ${logPath} || {
echo "❌ Docker build failed" >> ${logPath};
exit 1;
}
echo "✅ Docker build completed." >> ${logPath};
`; `;
return command; return command;

View File

@@ -62,8 +62,11 @@ export const getHerokuCommand = (
const command = `pack ${args.join(" ")}`; const command = `pack ${args.join(" ")}`;
const bashCommand = ` const bashCommand = `
echo "Starting heroku build..." >> ${logPath}; echo "Starting heroku build..." >> ${logPath};
${command} >> ${logPath} 2>&1; ${command} >> ${logPath} 2>> ${logPath} || {
echo "Heroku build completed." >> ${logPath}; echo "Heroku build failed" >> ${logPath};
exit 1;
}
echo "✅ Heroku build completed." >> ${logPath};
`; `;
return bashCommand; return bashCommand;

View File

@@ -16,7 +16,7 @@ import { buildCustomDocker, getDockerCommand } from "./docker-file";
import { buildHeroku, getHerokuCommand } from "./heroku"; import { buildHeroku, getHerokuCommand } from "./heroku";
import { buildNixpacks, getNixpacksCommand } from "./nixpacks"; import { buildNixpacks, getNixpacksCommand } from "./nixpacks";
import { buildPaketo, getPaketoCommand } from "./paketo"; import { buildPaketo, getPaketoCommand } from "./paketo";
import { buildStatic } from "./static"; import { buildStatic, getStaticCommand } from "./static";
import { findServerById } from "@/server/api/services/server"; import { findServerById } from "@/server/api/services/server";
import { readSSHKey } from "../filesystem/ssh"; import { readSSHKey } from "../filesystem/ssh";
import { getRemoteDocker } from "../servers/remote-docker"; import { getRemoteDocker } from "../servers/remote-docker";
@@ -81,8 +81,8 @@ export const getBuildCommand = (
return getHerokuCommand(application, logPath); return getHerokuCommand(application, logPath);
case "paketo_buildpacks": case "paketo_buildpacks":
return getPaketoCommand(application, logPath); return getPaketoCommand(application, logPath);
// case "static": case "static":
// return buildStatic(application, writeStream); return getStaticCommand(application, logPath);
case "dockerfile": case "dockerfile":
return getDockerCommand(application, logPath); return getDockerCommand(application, logPath);
} }

View File

@@ -1,12 +1,11 @@
import type { WriteStream } from "node:fs"; import type { WriteStream } from "node:fs";
import path from "node:path"; import path from "node:path";
import { buildStatic } from "@/server/utils/builders/static"; import { buildStatic, getStaticCommand } from "@/server/utils/builders/static";
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import type { ApplicationNested } from "."; import type { ApplicationNested } from ".";
import { prepareEnvironmentVariables } from "../docker/utils"; import { prepareEnvironmentVariables } from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory"; import { getBuildAppDirectory } from "../filesystem/directory";
import { spawnAsync } from "../process/spawnAsync"; import { spawnAsync } from "../process/spawnAsync";
import { executeCommand } from "../servers/command";
export const buildNixpacks = async ( export const buildNixpacks = async (
application: ApplicationNested, application: ApplicationNested,
@@ -83,7 +82,6 @@ export const getNixpacksCommand = (
const buildContainerId = `${appName}-${nanoid(10)}`; const buildContainerId = `${appName}-${nanoid(10)}`;
const envVariables = prepareEnvironmentVariables(env); const envVariables = prepareEnvironmentVariables(env);
try {
const args = ["build", buildAppDirectory, "--name", appName]; const args = ["build", buildAppDirectory, "--name", appName];
for (const env of envVariables) { for (const env of envVariables) {
@@ -96,10 +94,13 @@ export const getNixpacksCommand = (
} }
console.log("args", args); console.log("args", args);
const command = `nixpacks ${args.join(" ")}`; const command = `nixpacks ${args.join(" ")}`;
const bashCommand = ` let bashCommand = `
echo "Starting nixpacks build..." >> ${logPath}; echo "Starting nixpacks build..." >> ${logPath};
${command} >> ${logPath} 2>&1; ${command} >> ${logPath} 2>> ${logPath} || {
echo "Nixpacks build completed." >> ${logPath}; echo "Nixpacks build failed" >> ${logPath};
exit 1;
}
echo "✅ Nixpacks build completed." >> ${logPath};
`; `;
/* /*
@@ -107,23 +108,18 @@ echo "Nixpacks build completed." >> ${logPath};
and copy the artifacts on the host filesystem. and copy the artifacts on the host filesystem.
Then, remove the container and create a static build. Then, remove the container and create a static build.
*/ */
if (publishDirectory) { if (publishDirectory) {
bashCommand += `
docker create --name ${buildContainerId} ${appName}
docker cp ${buildContainerId}:/app/${publishDirectory} ${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)}
`;
} }
// if (publishDirectory) {
// bashCommand += `
// docker create --name ${buildContainerId} ${appName}
// docker cp ${buildContainerId}:/app/${publishDirectory} ${path.join(buildAppDirectory, publishDirectory)}
// docker rm ${buildContainerId}
// buildStatic ${application} ${writeStream}
// `;
// }
return bashCommand; return bashCommand;
} catch (e) {
// await spawnAsync("docker", ["rm", buildContainerId], writeToStream);
throw e;
}
}; };

View File

@@ -61,8 +61,11 @@ export const getPaketoCommand = (
const command = `pack ${args.join(" ")}`; const command = `pack ${args.join(" ")}`;
const bashCommand = ` const bashCommand = `
echo "Starting Paketo build..." >> ${logPath}; echo "Starting Paketo build..." >> ${logPath};
${command} >> ${logPath} 2>&1; ${command} >> ${logPath} 2>> ${logPath} || {
echo "Paketo build completed." >> ${logPath}; echo "Paketo build failed" >> ${logPath};
exit 1;
}
echo "✅ Paketo build completed." >> ${logPath};
`; `;
return bashCommand; return bashCommand;

View File

@@ -1,7 +1,10 @@
import type { WriteStream } from "node:fs"; import type { WriteStream } from "node:fs";
import { buildCustomDocker } from "@/server/utils/builders/docker-file"; import {
buildCustomDocker,
getDockerCommand,
} from "@/server/utils/builders/docker-file";
import type { ApplicationNested } from "."; import type { ApplicationNested } from ".";
import { createFile } from "../docker/utils"; import { createFile, getCreateFileCommand } from "../docker/utils";
import { getBuildAppDirectory } from "../filesystem/directory"; import { getBuildAppDirectory } from "../filesystem/directory";
export const buildStatic = async ( export const buildStatic = async (
@@ -36,3 +39,31 @@ export const buildStatic = async (
throw e; throw e;
} }
}; };
export const getStaticCommand = (
application: ApplicationNested,
logPath: string,
) => {
const { publishDirectory } = application;
const buildAppDirectory = getBuildAppDirectory(application);
let command = getCreateFileCommand(
buildAppDirectory,
"Dockerfile",
[
"FROM nginx:alpine",
"WORKDIR /usr/share/nginx/html/",
`COPY ${publishDirectory || "."} .`,
].join("\n"),
);
command += getDockerCommand(
{
...application,
buildType: "dockerfile",
dockerfile: "Dockerfile",
},
logPath,
);
return command;
};

View File

@@ -13,7 +13,6 @@ export const createEnvFile = (directory: string, env: string | null) => {
export const createEnvFileCommand = (directory: string, env: string | null) => { export const createEnvFileCommand = (directory: string, env: string | null) => {
const envFilePath = join(dirname(directory), ".env"); const envFilePath = join(dirname(directory), ".env");
// let command = ``
if (!existsSync(dirname(envFilePath))) { if (!existsSync(dirname(envFilePath))) {
mkdirSync(dirname(envFilePath), { recursive: true }); mkdirSync(dirname(envFilePath), { recursive: true });
} }

View File

@@ -96,7 +96,14 @@ export const loadDockerComposeRemote = async (
if (!compose.serverId) { if (!compose.serverId) {
return null; return null;
} }
const { stdout } = await execAsyncRemote(compose.serverId, `cat ${path}`); const { stdout, stderr } = await execAsyncRemote(
compose.serverId,
`cat ${path}`,
);
if (stderr) {
return null;
}
if (!stdout) return null; if (!stdout) return null;
const parsedConfig = load(stdout) as ComposeSpecification; const parsedConfig = load(stdout) as ComposeSpecification;
return parsedConfig; return parsedConfig;
@@ -135,21 +142,25 @@ export const writeDomainsToCompose = async (
export const writeDomainsToComposeRemote = async ( export const writeDomainsToComposeRemote = async (
compose: Compose, compose: Compose,
domains: Domain[], domains: Domain[],
logPath: string,
) => { ) => {
if (!domains.length) { if (!domains.length) {
return ""; return "";
} }
const composeConverted = await addDomainToCompose(compose, domains);
const path = getComposePath(compose);
try { try {
const composeConverted = await addDomainToCompose(compose, domains);
const path = getComposePath(compose);
if (compose.serverId) { if (compose.serverId) {
const composeString = dump(composeConverted, { lineWidth: 1000 }); const composeString = dump(composeConverted, { lineWidth: 1000 });
const encodedContent = encodeBase64(composeString); const encodedContent = encodeBase64(composeString);
return `echo "${encodedContent}" | base64 -d > "${path}";`; return `echo "${encodedContent}" | base64 -d > "${path}";`;
} }
} catch (error) { } catch (error) {
throw error; return `
echo "❌ Has occured an error: ${error?.message || error}" >> ${logPath};
exit 1;
`;
} }
}; };
// (node:59875) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGTERM listeners added to [process]. Use emitter.setMaxListeners() to increase limit // (node:59875) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGTERM listeners added to [process]. Use emitter.setMaxListeners() to increase limit

View File

@@ -59,24 +59,26 @@ export const buildRemoteDocker = async (
throw new Error("Docker image not found"); throw new Error("Docker image not found");
} }
let command = ` let command = `
echo "Building ${sourceType}" >> ${logPath};
echo "Pulling ${dockerImage}" >> ${logPath}; echo "Pulling ${dockerImage}" >> ${logPath};
`; `;
if (username && password) { if (username && password) {
command += ` command += `
if ! docker login --username ${username} --password ${password} https://index.docker.io/v1/ >> ${logPath} 2>&1; then if ! docker login --username ${username} --password ${password} https://index.docker.io/v1/ >> ${logPath} 2>&1; then
echo "Error logging in to Docker Hub" >> ${logPath}; echo "❌ Login failed" >> ${logPath};
exit 1; exit 1;
fi fi
`; `;
} }
command += ` command += `
echo "Pulling ${dockerImage}" >> ${logPath}; docker pull ${dockerImage} >> ${logPath} 2>> ${logPath} || {
docker pull ${dockerImage} >> ${logPath} 2>&1; echo "❌ Pulling image failed" >> ${logPath};
`; exit 1;
}
echo "✅ Pulling image completed." >> ${logPath};
`;
return command; return command;
} catch (error) { } catch (error) {
throw error; throw error;

View File

@@ -29,7 +29,10 @@ export const createComposeFile = async (compose: Compose, logPath: string) => {
} }
}; };
export const getCreateComposeFileCommand = (compose: Compose) => { export const getCreateComposeFileCommand = (
compose: Compose,
logPath: string,
) => {
const { appName, composeFile } = compose; const { appName, composeFile } = compose;
const outputPath = join(COMPOSE_PATH, appName, "code"); const outputPath = join(COMPOSE_PATH, appName, "code");
const filePath = join(outputPath, "docker-compose.yml"); const filePath = join(outputPath, "docker-compose.yml");
@@ -38,6 +41,7 @@ export const getCreateComposeFileCommand = (compose: Compose) => {
rm -rf ${outputPath}; rm -rf ${outputPath};
mkdir -p ${outputPath}; mkdir -p ${outputPath};
echo "${encodedContent}" | base64 -d > "${filePath}"; echo "${encodedContent}" | base64 -d > "${filePath}";
echo "File 'docker-compose.yml' created: ✅" >> ${logPath};
`; `;
return bashCommand; return bashCommand;
}; };