mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(rollback): add rollback constraints and snapshots
- Introduced two new SQL files for rollback constraints, updating foreign key relationships with different delete actions (set null and cascade). - Updated the journal and snapshot files to include the new rollback schema changes for versions 0096 and 0097. - Enhanced the application service to handle rollback image tagging based on source type. - Implemented rollback removal logic in the deployment service to ensure proper cleanup of rollback entries.
This commit is contained in:
3
apps/dokploy/drizzle/0096_small_shaman.sql
Normal file
3
apps/dokploy/drizzle/0096_small_shaman.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE "rollback" DROP CONSTRAINT "rollback_deploymentId_deployment_deploymentId_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "rollback" ADD CONSTRAINT "rollback_deploymentId_deployment_deploymentId_fk" FOREIGN KEY ("deploymentId") REFERENCES "public"."deployment"("deploymentId") ON DELETE set null ON UPDATE no action;
|
||||||
3
apps/dokploy/drizzle/0097_hard_lizard.sql
Normal file
3
apps/dokploy/drizzle/0097_hard_lizard.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE "rollback" DROP CONSTRAINT "rollback_deploymentId_deployment_deploymentId_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "rollback" ADD CONSTRAINT "rollback_deploymentId_deployment_deploymentId_fk" FOREIGN KEY ("deploymentId") REFERENCES "public"."deployment"("deploymentId") ON DELETE cascade ON UPDATE no action;
|
||||||
5826
apps/dokploy/drizzle/meta/0096_snapshot.json
Normal file
5826
apps/dokploy/drizzle/meta/0096_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
5826
apps/dokploy/drizzle/meta/0097_snapshot.json
Normal file
5826
apps/dokploy/drizzle/meta/0097_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -673,6 +673,20 @@
|
|||||||
"when": 1750562292392,
|
"when": 1750562292392,
|
||||||
"tag": "0095_curly_justice",
|
"tag": "0095_curly_justice",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 96,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1750566830268,
|
||||||
|
"tag": "0096_small_shaman",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 97,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1750567641441,
|
||||||
|
"tag": "0097_hard_lizard",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -216,8 +216,12 @@ export const deployApplication = async ({
|
|||||||
await updateApplicationStatus(applicationId, "done");
|
await updateApplicationStatus(applicationId, "done");
|
||||||
|
|
||||||
if (application.rollbackActive) {
|
if (application.rollbackActive) {
|
||||||
|
const tagImage =
|
||||||
|
application.sourceType === "docker"
|
||||||
|
? application.dockerImage
|
||||||
|
: application.appName;
|
||||||
await createRollback({
|
await createRollback({
|
||||||
appName: application.appName,
|
appName: tagImage || "",
|
||||||
deploymentId: deployment.deploymentId,
|
deploymentId: deployment.deploymentId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import {
|
|||||||
updatePreviewDeployment,
|
updatePreviewDeployment,
|
||||||
} from "./preview-deployment";
|
} from "./preview-deployment";
|
||||||
import { findScheduleById } from "./schedule";
|
import { findScheduleById } from "./schedule";
|
||||||
|
import { removeRollbackById } from "./rollbacks";
|
||||||
|
|
||||||
export type Deployment = typeof deployments.$inferSelect;
|
export type Deployment = typeof deployments.$inferSelect;
|
||||||
|
|
||||||
@@ -495,6 +496,9 @@ const getDeploymentsByType = async (
|
|||||||
const deploymentList = await db.query.deployments.findMany({
|
const deploymentList = await db.query.deployments.findMany({
|
||||||
where: eq(deployments[`${type}Id`], id),
|
where: eq(deployments[`${type}Id`], id),
|
||||||
orderBy: desc(deployments.createdAt),
|
orderBy: desc(deployments.createdAt),
|
||||||
|
with: {
|
||||||
|
rollback: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return deploymentList;
|
return deploymentList;
|
||||||
};
|
};
|
||||||
@@ -529,6 +533,9 @@ const removeLastTenDeployments = async (
|
|||||||
let command = "";
|
let command = "";
|
||||||
for (const oldDeployment of deploymentsToDelete) {
|
for (const oldDeployment of deploymentsToDelete) {
|
||||||
const logPath = path.join(oldDeployment.logPath);
|
const logPath = path.join(oldDeployment.logPath);
|
||||||
|
if (oldDeployment.rollbackId) {
|
||||||
|
await removeRollbackById(oldDeployment.rollbackId);
|
||||||
|
}
|
||||||
|
|
||||||
command += `
|
command += `
|
||||||
rm -rf ${logPath};
|
rm -rf ${logPath};
|
||||||
@@ -539,8 +546,11 @@ const removeLastTenDeployments = async (
|
|||||||
await execAsyncRemote(serverId, command);
|
await execAsyncRemote(serverId, command);
|
||||||
} else {
|
} else {
|
||||||
for (const oldDeployment of deploymentsToDelete) {
|
for (const oldDeployment of deploymentsToDelete) {
|
||||||
|
if (oldDeployment.rollbackId) {
|
||||||
|
await removeRollbackById(oldDeployment.rollbackId);
|
||||||
|
}
|
||||||
const logPath = path.join(oldDeployment.logPath);
|
const logPath = path.join(oldDeployment.logPath);
|
||||||
if (existsSync(logPath)) {
|
if (existsSync(logPath) && !oldDeployment.errorMessage) {
|
||||||
await fsPromises.unlink(logPath);
|
await fsPromises.unlink(logPath);
|
||||||
}
|
}
|
||||||
await removeDeployment(oldDeployment.deploymentId);
|
await removeDeployment(oldDeployment.deploymentId);
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "../db";
|
import { db } from "../db";
|
||||||
import { type createRollbackSchema, rollbacks } from "../db/schema";
|
import {
|
||||||
|
type createRollbackSchema,
|
||||||
|
rollbacks,
|
||||||
|
deployments as deploymentsSchema,
|
||||||
|
} from "../db/schema";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import { findApplicationById } from "./application";
|
import { findApplicationById } from "./application";
|
||||||
import { getRemoteDocker } from "../utils/servers/remote-docker";
|
import { getRemoteDocker } from "../utils/servers/remote-docker";
|
||||||
@@ -30,8 +34,14 @@ export const createRollback = async (
|
|||||||
throw new Error("Deployment not found");
|
throw new Error("Deployment not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { deployments, bitbucket, github, gitlab, gitea, ...rest } =
|
const {
|
||||||
await findApplicationById(deployment.applicationId);
|
deployments: _,
|
||||||
|
bitbucket,
|
||||||
|
github,
|
||||||
|
gitlab,
|
||||||
|
gitea,
|
||||||
|
...rest
|
||||||
|
} = await findApplicationById(deployment.applicationId);
|
||||||
|
|
||||||
await tx
|
await tx
|
||||||
.update(rollbacks)
|
.update(rollbacks)
|
||||||
@@ -41,6 +51,14 @@ export const createRollback = async (
|
|||||||
})
|
})
|
||||||
.where(eq(rollbacks.rollbackId, rollback.rollbackId));
|
.where(eq(rollbacks.rollbackId, rollback.rollbackId));
|
||||||
|
|
||||||
|
// Update the deployment to reference this rollback
|
||||||
|
await tx
|
||||||
|
.update(deploymentsSchema)
|
||||||
|
.set({
|
||||||
|
rollbackId: rollback.rollbackId,
|
||||||
|
})
|
||||||
|
.where(eq(deploymentsSchema.deploymentId, rollback.deploymentId));
|
||||||
|
|
||||||
await createRollbackImage(rest, tagImage);
|
await createRollbackImage(rest, tagImage);
|
||||||
|
|
||||||
return rollback;
|
return rollback;
|
||||||
@@ -65,12 +83,17 @@ const createRollbackImage = async (
|
|||||||
) => {
|
) => {
|
||||||
const docker = await getRemoteDocker(application.serverId);
|
const docker = await getRemoteDocker(application.serverId);
|
||||||
|
|
||||||
const result = docker.getImage(`${application.appName}:latest`);
|
const appTagName =
|
||||||
|
application.sourceType === "docker"
|
||||||
|
? application.dockerImage
|
||||||
|
: `${application.appName}:latest`;
|
||||||
|
|
||||||
const version = tagImage.split(":")[1];
|
const result = docker.getImage(appTagName || "");
|
||||||
|
|
||||||
|
const [repo, version] = tagImage.split(":");
|
||||||
|
|
||||||
await result.tag({
|
await result.tag({
|
||||||
repo: tagImage,
|
repo,
|
||||||
tag: version,
|
tag: version,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -86,28 +109,34 @@ const deleteRollbackImage = async (image: string, serverId?: string | null) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const removeRollbackById = async (rollbackId: string) => {
|
export const removeRollbackById = async (rollbackId: string) => {
|
||||||
const result = await db
|
const rollback = await findRollbackById(rollbackId);
|
||||||
.delete(rollbacks)
|
|
||||||
.where(eq(rollbacks.rollbackId, rollbackId))
|
|
||||||
.returning()
|
|
||||||
.then((res) => res[0]);
|
|
||||||
|
|
||||||
if (result?.image) {
|
if (!rollback) {
|
||||||
|
throw new Error("Rollback not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rollback?.image) {
|
||||||
try {
|
try {
|
||||||
const deployment = await findDeploymentById(result.deploymentId);
|
const deployment = await findDeploymentById(rollback.deploymentId);
|
||||||
|
|
||||||
if (!deployment?.applicationId) {
|
if (!deployment?.applicationId) {
|
||||||
throw new Error("Deployment not found");
|
throw new Error("Deployment not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const application = await findApplicationById(deployment.applicationId);
|
const application = await findApplicationById(deployment.applicationId);
|
||||||
await deleteRollbackImage(result.image, application.serverId);
|
await deleteRollbackImage(rollback.image, application.serverId);
|
||||||
|
|
||||||
|
await db
|
||||||
|
.delete(rollbacks)
|
||||||
|
.where(eq(rollbacks.rollbackId, rollbackId))
|
||||||
|
.returning()
|
||||||
|
.then((res) => res[0]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return rollback;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const rollback = async (rollbackId: string) => {
|
export const rollback = async (rollbackId: string) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user