mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat(application): add cleanCache feature to application management
- Introduced a new boolean column `cleanCache` in the application schema to manage cache cleaning behavior. - Updated the application form to include a toggle for `cleanCache`, allowing users to enable or disable cache cleaning. - Enhanced application deployment logic to utilize the `cleanCache` setting, affecting build commands across various builders (Docker, Heroku, Nixpacks, Paketo, Railpack). - Implemented success and error notifications for cache updates in the UI.
This commit is contained in:
parent
9ac68985e0
commit
40718293a1
@ -267,6 +267,28 @@ export const ShowGeneralApplication = ({ applicationId }: Props) => {
|
||||
className="flex flex-row gap-2 items-center"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center gap-2 rounded-md px-4 py-2 border">
|
||||
<span className="text-sm font-medium">Clean Cache</span>
|
||||
<Switch
|
||||
aria-label="Toggle italic"
|
||||
checked={data?.cleanCache || false}
|
||||
onCheckedChange={async (enabled) => {
|
||||
await update({
|
||||
applicationId,
|
||||
cleanCache: enabled,
|
||||
})
|
||||
.then(async () => {
|
||||
toast.success("Clean Cache Updated");
|
||||
await refetch();
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Error updating Clean Cache");
|
||||
});
|
||||
}}
|
||||
className="flex flex-row gap-2 items-center"
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<ShowProviderForm applicationId={applicationId} />
|
||||
|
1
apps/dokploy/drizzle/0078_uneven_omega_sentinel.sql
Normal file
1
apps/dokploy/drizzle/0078_uneven_omega_sentinel.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE "application" ADD COLUMN "cleanCache" boolean DEFAULT false;
|
5163
apps/dokploy/drizzle/meta/0078_snapshot.json
Normal file
5163
apps/dokploy/drizzle/meta/0078_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -547,6 +547,13 @@
|
||||
"when": 1741510086231,
|
||||
"tag": "0077_chemical_dreadnoughts",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 78,
|
||||
"version": "7",
|
||||
"when": 1742112194375,
|
||||
"tag": "0078_uneven_omega_sentinel",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
@ -141,6 +141,7 @@ export const applications = pgTable("application", {
|
||||
command: text("command"),
|
||||
refreshToken: text("refreshToken").$defaultFn(() => nanoid()),
|
||||
sourceType: sourceType("sourceType").notNull().default("github"),
|
||||
cleanCache: boolean("cleanCache").default(false),
|
||||
// Github
|
||||
repository: text("repository"),
|
||||
owner: text("owner"),
|
||||
@ -408,6 +409,7 @@ const createSchema = createInsertSchema(applications, {
|
||||
previewPath: z.string().optional(),
|
||||
previewCertificateType: z.enum(["letsencrypt", "none", "custom"]).optional(),
|
||||
watchPaths: z.array(z.string()).optional(),
|
||||
cleanCache: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export const apiCreateApplication = createSchema.pick({
|
||||
|
@ -159,6 +159,7 @@ table application {
|
||||
command text
|
||||
refreshToken text
|
||||
sourceType sourceType [not null, default: 'github']
|
||||
cleanCache boolean [default: false]
|
||||
repository text
|
||||
owner text
|
||||
branch text
|
||||
|
@ -182,12 +182,6 @@ export const deployApplication = async ({
|
||||
});
|
||||
|
||||
try {
|
||||
// const admin = await findUserById(application.project.userId);
|
||||
|
||||
// if (admin.cleanupCacheApplications) {
|
||||
// await cleanupFullDocker(application?.serverId);
|
||||
// }
|
||||
|
||||
if (application.sourceType === "github") {
|
||||
await cloneGithubRepository({
|
||||
...application,
|
||||
@ -257,11 +251,6 @@ export const rebuildApplication = async ({
|
||||
});
|
||||
|
||||
try {
|
||||
// const admin = await findUserById(application.project.userId);
|
||||
|
||||
// if (admin.cleanupCacheApplications) {
|
||||
// await cleanupFullDocker(application?.serverId);
|
||||
// }
|
||||
if (application.sourceType === "github") {
|
||||
await buildApplication(application, deployment.logPath);
|
||||
} else if (application.sourceType === "gitlab") {
|
||||
@ -306,11 +295,6 @@ export const deployRemoteApplication = async ({
|
||||
|
||||
try {
|
||||
if (application.serverId) {
|
||||
// const admin = await findUserById(application.project.userId);
|
||||
|
||||
// if (admin.cleanupCacheApplications) {
|
||||
// await cleanupFullDocker(application?.serverId);
|
||||
// }
|
||||
let command = "set -e;";
|
||||
if (application.sourceType === "github") {
|
||||
command += await getGithubCloneCommand({
|
||||
@ -451,12 +435,6 @@ export const deployPreviewApplication = async ({
|
||||
application.env = `${application.previewEnv}\nDOKPLOY_DEPLOY_URL=${previewDeployment?.domain?.host}`;
|
||||
application.buildArgs = application.previewBuildArgs;
|
||||
|
||||
// const admin = await findUserById(application.project.userId);
|
||||
|
||||
// if (admin.cleanupCacheOnPreviews) {
|
||||
// await cleanupFullDocker(application?.serverId);
|
||||
// }
|
||||
|
||||
if (application.sourceType === "github") {
|
||||
await cloneGithubRepository({
|
||||
...application,
|
||||
@ -565,11 +543,6 @@ export const deployRemotePreviewApplication = async ({
|
||||
application.buildArgs = application.previewBuildArgs;
|
||||
|
||||
if (application.serverId) {
|
||||
// const admin = await findUserById(application.project.userId);
|
||||
|
||||
// if (admin.cleanupCacheOnPreviews) {
|
||||
// await cleanupFullDocker(application?.serverId);
|
||||
// }
|
||||
let command = "set -e;";
|
||||
if (application.sourceType === "github") {
|
||||
command += await getGithubCloneCommand({
|
||||
@ -634,11 +607,6 @@ export const rebuildRemoteApplication = async ({
|
||||
|
||||
try {
|
||||
if (application.serverId) {
|
||||
// const admin = await findUserById(application.project.userId);
|
||||
|
||||
// if (admin.cleanupCacheApplications) {
|
||||
// await cleanupFullDocker(application?.serverId);
|
||||
// }
|
||||
if (application.sourceType !== "docker") {
|
||||
let command = "set -e;";
|
||||
command += getBuildCommand(application, deployment.logPath);
|
||||
|
@ -216,10 +216,6 @@ export const deployCompose = async ({
|
||||
});
|
||||
|
||||
try {
|
||||
// const admin = await findUserById(compose.project.userId);
|
||||
// if (admin.cleanupCacheOnCompose) {
|
||||
// await cleanupFullDocker(compose?.serverId);
|
||||
// }
|
||||
if (compose.sourceType === "github") {
|
||||
await cloneGithubRepository({
|
||||
...compose,
|
||||
@ -285,11 +281,6 @@ export const rebuildCompose = async ({
|
||||
});
|
||||
|
||||
try {
|
||||
// const admin = await findUserById(compose.project.userId);
|
||||
// if (admin.cleanupCacheOnCompose) {
|
||||
// await cleanupFullDocker(compose?.serverId);
|
||||
// }
|
||||
|
||||
if (compose.sourceType === "raw") {
|
||||
await createComposeFile(compose, deployment.logPath);
|
||||
}
|
||||
@ -331,10 +322,6 @@ export const deployRemoteCompose = async ({
|
||||
});
|
||||
try {
|
||||
if (compose.serverId) {
|
||||
// const admin = await findUserById(compose.project.userId);
|
||||
// if (admin.cleanupCacheOnCompose) {
|
||||
// await cleanupFullDocker(compose?.serverId);
|
||||
// }
|
||||
let command = "set -e;";
|
||||
|
||||
if (compose.sourceType === "github") {
|
||||
@ -429,10 +416,6 @@ export const rebuildRemoteCompose = async ({
|
||||
});
|
||||
|
||||
try {
|
||||
// const admin = await findUserById(compose.project.userId);
|
||||
// if (admin.cleanupCacheOnCompose) {
|
||||
// await cleanupFullDocker(compose?.serverId);
|
||||
// }
|
||||
if (compose.sourceType === "raw") {
|
||||
const command = getCreateComposeFileCommand(compose, deployment.logPath);
|
||||
await execAsyncRemote(compose.serverId, command);
|
||||
|
@ -12,8 +12,14 @@ export const buildCustomDocker = async (
|
||||
application: ApplicationNested,
|
||||
writeStream: WriteStream,
|
||||
) => {
|
||||
const { appName, env, publishDirectory, buildArgs, dockerBuildStage } =
|
||||
application;
|
||||
const {
|
||||
appName,
|
||||
env,
|
||||
publishDirectory,
|
||||
buildArgs,
|
||||
dockerBuildStage,
|
||||
cleanCache,
|
||||
} = application;
|
||||
const dockerFilePath = getBuildAppDirectory(application);
|
||||
try {
|
||||
const image = `${appName}`;
|
||||
@ -29,6 +35,10 @@ export const buildCustomDocker = async (
|
||||
|
||||
const commandArgs = ["build", "-t", image, "-f", dockerFilePath, "."];
|
||||
|
||||
if (cleanCache) {
|
||||
commandArgs.push("--no-cache");
|
||||
}
|
||||
|
||||
if (dockerBuildStage) {
|
||||
commandArgs.push("--target", dockerBuildStage);
|
||||
}
|
||||
@ -65,8 +75,14 @@ export const getDockerCommand = (
|
||||
application: ApplicationNested,
|
||||
logPath: string,
|
||||
) => {
|
||||
const { appName, env, publishDirectory, buildArgs, dockerBuildStage } =
|
||||
application;
|
||||
const {
|
||||
appName,
|
||||
env,
|
||||
publishDirectory,
|
||||
buildArgs,
|
||||
dockerBuildStage,
|
||||
cleanCache,
|
||||
} = application;
|
||||
const dockerFilePath = getBuildAppDirectory(application);
|
||||
|
||||
try {
|
||||
@ -88,6 +104,10 @@ export const getDockerCommand = (
|
||||
commandArgs.push("--target", dockerBuildStage);
|
||||
}
|
||||
|
||||
if (cleanCache) {
|
||||
commandArgs.push("--no-cache");
|
||||
}
|
||||
|
||||
for (const arg of args) {
|
||||
commandArgs.push("--build-arg", arg);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export const buildHeroku = async (
|
||||
application: ApplicationNested,
|
||||
writeStream: WriteStream,
|
||||
) => {
|
||||
const { env, appName } = application;
|
||||
const { env, appName, cleanCache } = application;
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const envVariables = prepareEnvironmentVariables(
|
||||
env,
|
||||
@ -29,6 +29,10 @@ export const buildHeroku = async (
|
||||
args.push("--env", env);
|
||||
}
|
||||
|
||||
if (cleanCache) {
|
||||
args.push("--clear-cache");
|
||||
}
|
||||
|
||||
await spawnAsync("pack", args, (data) => {
|
||||
if (writeStream.writable) {
|
||||
writeStream.write(data);
|
||||
@ -44,7 +48,7 @@ export const getHerokuCommand = (
|
||||
application: ApplicationNested,
|
||||
logPath: string,
|
||||
) => {
|
||||
const { env, appName } = application;
|
||||
const { env, appName, cleanCache } = application;
|
||||
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const envVariables = prepareEnvironmentVariables(
|
||||
@ -61,6 +65,10 @@ export const getHerokuCommand = (
|
||||
`heroku/builder:${application.herokuVersion || "24"}`,
|
||||
];
|
||||
|
||||
if (cleanCache) {
|
||||
args.push("--clear-cache");
|
||||
}
|
||||
|
||||
for (const env of envVariables) {
|
||||
args.push("--env", `'${env}'`);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ export const buildNixpacks = async (
|
||||
application: ApplicationNested,
|
||||
writeStream: WriteStream,
|
||||
) => {
|
||||
const { env, appName, publishDirectory } = application;
|
||||
const { env, appName, publishDirectory, cleanCache } = application;
|
||||
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const buildContainerId = `${appName}-${nanoid(10)}`;
|
||||
@ -32,6 +32,10 @@ export const buildNixpacks = async (
|
||||
try {
|
||||
const args = ["build", buildAppDirectory, "--name", appName];
|
||||
|
||||
if (cleanCache) {
|
||||
args.push("--no-cache");
|
||||
}
|
||||
|
||||
for (const env of envVariables) {
|
||||
args.push("--env", env);
|
||||
}
|
||||
@ -91,7 +95,7 @@ export const getNixpacksCommand = (
|
||||
application: ApplicationNested,
|
||||
logPath: string,
|
||||
) => {
|
||||
const { env, appName, publishDirectory } = application;
|
||||
const { env, appName, publishDirectory, cleanCache } = application;
|
||||
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const buildContainerId = `${appName}-${nanoid(10)}`;
|
||||
@ -102,6 +106,10 @@ export const getNixpacksCommand = (
|
||||
|
||||
const args = ["build", buildAppDirectory, "--name", appName];
|
||||
|
||||
if (cleanCache) {
|
||||
args.push("--no-cache");
|
||||
}
|
||||
|
||||
for (const env of envVariables) {
|
||||
args.push("--env", `'${env}'`);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ export const buildPaketo = async (
|
||||
application: ApplicationNested,
|
||||
writeStream: WriteStream,
|
||||
) => {
|
||||
const { env, appName } = application;
|
||||
const { env, appName, cleanCache } = application;
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const envVariables = prepareEnvironmentVariables(
|
||||
env,
|
||||
@ -24,6 +24,10 @@ export const buildPaketo = async (
|
||||
"paketobuildpacks/builder-jammy-full",
|
||||
];
|
||||
|
||||
if (cleanCache) {
|
||||
args.push("--clear-cache");
|
||||
}
|
||||
|
||||
for (const env of envVariables) {
|
||||
args.push("--env", env);
|
||||
}
|
||||
@ -43,7 +47,7 @@ export const getPaketoCommand = (
|
||||
application: ApplicationNested,
|
||||
logPath: string,
|
||||
) => {
|
||||
const { env, appName } = application;
|
||||
const { env, appName, cleanCache } = application;
|
||||
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const envVariables = prepareEnvironmentVariables(
|
||||
@ -60,6 +64,10 @@ export const getPaketoCommand = (
|
||||
"paketobuildpacks/builder-jammy-full",
|
||||
];
|
||||
|
||||
if (cleanCache) {
|
||||
args.push("--clear-cache");
|
||||
}
|
||||
|
||||
for (const env of envVariables) {
|
||||
args.push("--env", `'${env}'`);
|
||||
}
|
||||
|
@ -4,12 +4,22 @@ import { prepareEnvironmentVariables } from "../docker/utils";
|
||||
import { getBuildAppDirectory } from "../filesystem/directory";
|
||||
import { spawnAsync } from "../process/spawnAsync";
|
||||
import { execAsync } from "../process/execAsync";
|
||||
import { nanoid } from "nanoid";
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
const calculateSecretsHash = (envVariables: string[]): string => {
|
||||
const hash = createHash("sha256");
|
||||
for (const env of envVariables.sort()) {
|
||||
hash.update(env);
|
||||
}
|
||||
return hash.digest("hex");
|
||||
};
|
||||
|
||||
export const buildRailpack = async (
|
||||
application: ApplicationNested,
|
||||
writeStream: WriteStream,
|
||||
) => {
|
||||
const { env, appName } = application;
|
||||
const { env, appName, cleanCache } = application;
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const envVariables = prepareEnvironmentVariables(
|
||||
env,
|
||||
@ -45,10 +55,22 @@ export const buildRailpack = async (
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate secrets hash for layer invalidation
|
||||
const secretsHash = calculateSecretsHash(envVariables);
|
||||
|
||||
// Build with BuildKit using the Railpack frontend
|
||||
const cacheKey = cleanCache ? nanoid(10) : undefined;
|
||||
const buildArgs = [
|
||||
"buildx",
|
||||
"build",
|
||||
...(cacheKey
|
||||
? [
|
||||
"--build-arg",
|
||||
`secrets-hash=${secretsHash}`,
|
||||
"--build-arg",
|
||||
`cache-key=${cacheKey}`,
|
||||
]
|
||||
: []),
|
||||
"--build-arg",
|
||||
"BUILDKIT_SYNTAX=ghcr.io/railwayapp/railpack-frontend:v0.0.55",
|
||||
"-f",
|
||||
@ -92,7 +114,7 @@ export const getRailpackCommand = (
|
||||
application: ApplicationNested,
|
||||
logPath: string,
|
||||
) => {
|
||||
const { env, appName } = application;
|
||||
const { env, appName, cleanCache } = application;
|
||||
const buildAppDirectory = getBuildAppDirectory(application);
|
||||
const envVariables = prepareEnvironmentVariables(
|
||||
env,
|
||||
@ -113,10 +135,22 @@ export const getRailpackCommand = (
|
||||
prepareArgs.push("--env", env);
|
||||
}
|
||||
|
||||
// Calculate secrets hash for layer invalidation
|
||||
const secretsHash = calculateSecretsHash(envVariables);
|
||||
|
||||
const cacheKey = cleanCache ? nanoid(10) : undefined;
|
||||
// Build command
|
||||
const buildArgs = [
|
||||
"buildx",
|
||||
"build",
|
||||
...(cacheKey
|
||||
? [
|
||||
"--build-arg",
|
||||
`secrets-hash=${secretsHash}`,
|
||||
"--build-arg",
|
||||
`cache-key=${cacheKey}`,
|
||||
]
|
||||
: []),
|
||||
"--build-arg",
|
||||
"BUILDKIT_SYNTAX=ghcr.io/railwayapp/railpack-frontend:v0.0.55",
|
||||
"-f",
|
||||
|
Loading…
Reference in New Issue
Block a user