mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-19 22:25:22 +02:00
Merge branch 'canary' into feature/stop-grace-period-2227
This commit is contained in:
@@ -17,7 +17,7 @@ export const runComposeBackup = async (
|
||||
const project = await findProjectById(projectId);
|
||||
const { prefix, databaseType } = backup;
|
||||
const destination = backup.destination;
|
||||
const backupFileName = `${new Date().toISOString()}.dump.gz`;
|
||||
const backupFileName = `${new Date().toISOString()}.sql.gz`;
|
||||
const bucketDestination = `${normalizeS3Path(prefix)}${backupFileName}`;
|
||||
const deployment = await createDeploymentBackup({
|
||||
backupId: backup.backupId,
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import path from "node:path";
|
||||
import { member } from "@dokploy/server/db/schema";
|
||||
import type { BackupSchedule } from "@dokploy/server/services/backup";
|
||||
import { getAllServers } from "@dokploy/server/services/server";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { scheduleJob } from "node-schedule";
|
||||
import { db } from "../../db/index";
|
||||
import { startLogCleanup } from "../access-log/handler";
|
||||
import {
|
||||
cleanUpDockerBuilder,
|
||||
cleanUpSystemPrune,
|
||||
@@ -11,11 +15,6 @@ import { sendDockerCleanupNotifications } from "../notifications/docker-cleanup"
|
||||
import { execAsync, execAsyncRemote } from "../process/execAsync";
|
||||
import { getS3Credentials, scheduleBackup } from "./utils";
|
||||
|
||||
import { member } from "@dokploy/server/db/schema";
|
||||
import type { BackupSchedule } from "@dokploy/server/services/backup";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { startLogCleanup } from "../access-log/handler";
|
||||
|
||||
export const initCronJobs = async () => {
|
||||
console.log("Setting up cron jobs....");
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
|
||||
const project = await findProjectById(projectId);
|
||||
const { prefix } = backup;
|
||||
const destination = backup.destination;
|
||||
const backupFileName = `${new Date().toISOString()}.dump.gz`;
|
||||
const backupFileName = `${new Date().toISOString()}.sql.gz`;
|
||||
const bucketDestination = `${normalizeS3Path(prefix)}${backupFileName}`;
|
||||
const deployment = await createDeploymentBackup({
|
||||
backupId: backup.backupId,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import type { WriteStream } from "node:fs";
|
||||
import { nanoid } from "nanoid";
|
||||
import type { ApplicationNested } from ".";
|
||||
import {
|
||||
parseEnvironmentKeyValuePair,
|
||||
prepareEnvironmentVariables,
|
||||
@@ -9,6 +8,7 @@ import {
|
||||
import { getBuildAppDirectory } from "../filesystem/directory";
|
||||
import { execAsync } from "../process/execAsync";
|
||||
import { spawnAsync } from "../process/spawnAsync";
|
||||
import type { ApplicationNested } from ".";
|
||||
|
||||
const calculateSecretsHash = (envVariables: string[]): string => {
|
||||
const hash = createHash("sha256");
|
||||
@@ -75,7 +75,7 @@ export const buildRailpack = async (
|
||||
]
|
||||
: []),
|
||||
"--build-arg",
|
||||
"BUILDKIT_SYNTAX=ghcr.io/railwayapp/railpack-frontend:v0.0.64",
|
||||
"BUILDKIT_SYNTAX=ghcr.io/railwayapp/railpack-frontend:v0.2.2",
|
||||
"-f",
|
||||
`${buildAppDirectory}/railpack-plan.json`,
|
||||
"--output",
|
||||
|
||||
@@ -313,40 +313,46 @@ export const createDomainLabels = (
|
||||
`traefik.http.routers.${routerName}.service=${routerName}`,
|
||||
];
|
||||
|
||||
// Validate stripPath - it should only be used when path is defined and not "/"
|
||||
if (stripPath) {
|
||||
if (!path || path === "/") {
|
||||
console.warn(
|
||||
`stripPath is enabled but path is not defined or is "/" for domain ${host}`,
|
||||
);
|
||||
} else {
|
||||
const middlewareName = `stripprefix-${appName}-${uniqueConfigKey}`;
|
||||
// Collect middlewares for this router
|
||||
const middlewares: string[] = [];
|
||||
|
||||
// Add HTTPS redirect for web entrypoint (must be first)
|
||||
if (entrypoint === "web" && https) {
|
||||
middlewares.push("redirect-to-https@file");
|
||||
}
|
||||
|
||||
// Add stripPath middleware if needed
|
||||
if (stripPath && path && path !== "/") {
|
||||
const middlewareName = `stripprefix-${appName}-${uniqueConfigKey}`;
|
||||
// Only define middleware once (on web entrypoint)
|
||||
if (entrypoint === "web") {
|
||||
labels.push(
|
||||
`traefik.http.middlewares.${middlewareName}.stripprefix.prefixes=${path}`,
|
||||
);
|
||||
}
|
||||
middlewares.push(middlewareName);
|
||||
}
|
||||
|
||||
// Validate internalPath - ensure it's a valid path format
|
||||
if (internalPath && internalPath !== "/") {
|
||||
if (!internalPath.startsWith("/")) {
|
||||
console.warn(
|
||||
`internalPath "${internalPath}" should start with "/" and not be empty for domain ${host}`,
|
||||
);
|
||||
} else {
|
||||
const middlewareName = `addprefix-${appName}-${uniqueConfigKey}`;
|
||||
// Add internalPath middleware if needed
|
||||
if (internalPath && internalPath !== "/" && internalPath.startsWith("/")) {
|
||||
const middlewareName = `addprefix-${appName}-${uniqueConfigKey}`;
|
||||
// Only define middleware once (on web entrypoint)
|
||||
if (entrypoint === "web") {
|
||||
labels.push(
|
||||
`traefik.http.middlewares.${middlewareName}.addprefix.prefix=${internalPath}`,
|
||||
);
|
||||
}
|
||||
middlewares.push(middlewareName);
|
||||
}
|
||||
|
||||
if (entrypoint === "web" && https) {
|
||||
// Apply middlewares to router if any exist
|
||||
if (middlewares.length > 0) {
|
||||
labels.push(
|
||||
`traefik.http.routers.${routerName}.middlewares=redirect-to-https@file`,
|
||||
`traefik.http.routers.${routerName}.middlewares=${middlewares.join(",")}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Add TLS configuration for websecure
|
||||
if (entrypoint === "websecure") {
|
||||
if (certificateType === "letsencrypt") {
|
||||
labels.push(
|
||||
|
||||
@@ -65,6 +65,8 @@ export const sendBuildErrorNotifications = async ({
|
||||
const decorate = (decoration: string, text: string) =>
|
||||
`${discord.decoration ? decoration : ""} ${text}`.trim();
|
||||
|
||||
const limitCharacter = 800;
|
||||
const truncatedErrorMessage = errorMessage.substring(0, limitCharacter);
|
||||
await sendDiscordNotification(discord, {
|
||||
title: decorate(">", "`⚠️` Build Failed"),
|
||||
color: 0xed4245,
|
||||
@@ -101,7 +103,7 @@ export const sendBuildErrorNotifications = async ({
|
||||
},
|
||||
{
|
||||
name: decorate("`⚠️`", "Error Message"),
|
||||
value: `\`\`\`${errorMessage}\`\`\``,
|
||||
value: `\`\`\`${truncatedErrorMessage}\`\`\``,
|
||||
},
|
||||
{
|
||||
name: decorate("`🧷`", "Build Link"),
|
||||
|
||||
@@ -4,8 +4,8 @@ import { paths } from "@dokploy/server/constants";
|
||||
import type { apiGitlabTestConnection } from "@dokploy/server/db/schema";
|
||||
import type { Compose } from "@dokploy/server/services/compose";
|
||||
import {
|
||||
type Gitlab,
|
||||
findGitlabById,
|
||||
type Gitlab,
|
||||
updateGitlab,
|
||||
} from "@dokploy/server/services/gitlab";
|
||||
import type { InferResultType } from "@dokploy/server/types/with";
|
||||
@@ -310,22 +310,43 @@ export const getGitlabBranches = async (input: {
|
||||
|
||||
const gitlabProvider = await findGitlabById(input.gitlabId);
|
||||
|
||||
const branchesResponse = await fetch(
|
||||
`${gitlabProvider.gitlabUrl}/api/v4/projects/${input.id}/repository/branches`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
const allBranches = [];
|
||||
let page = 1;
|
||||
const perPage = 100; // GitLab's max per page is 100
|
||||
|
||||
if (!branchesResponse.ok) {
|
||||
throw new Error(`Failed to fetch branches: ${branchesResponse.statusText}`);
|
||||
while (true) {
|
||||
const branchesResponse = await fetch(
|
||||
`https://gitlab.com/api/v4/projects/${input.id}/repository/branches?page=${page}&per_page=${perPage}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!branchesResponse.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch branches: ${branchesResponse.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const branches = await branchesResponse.json();
|
||||
|
||||
if (branches.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
allBranches.push(...branches);
|
||||
page++;
|
||||
|
||||
// Check if we've reached the total using headers (optional optimization)
|
||||
const total = branchesResponse.headers.get("x-total");
|
||||
if (total && allBranches.length >= Number.parseInt(total)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const branches = await branchesResponse.json();
|
||||
|
||||
return branches as {
|
||||
return allBranches as {
|
||||
id: string;
|
||||
name: string;
|
||||
commit: {
|
||||
|
||||
@@ -81,7 +81,7 @@ const getMongoSpecificCommand = (
|
||||
backupFile: string,
|
||||
): string => {
|
||||
const tempDir = "/tmp/dokploy-restore";
|
||||
const fileName = backupFile.split("/").pop() || "backup.dump.gz";
|
||||
const fileName = backupFile.split("/").pop() || "backup.sql.gz";
|
||||
const decompressedName = fileName.replace(".gz", "");
|
||||
return `
|
||||
rm -rf ${tempDir} && \
|
||||
|
||||
@@ -2,8 +2,7 @@ import path from "node:path";
|
||||
import { paths } from "@dokploy/server/constants";
|
||||
import { findComposeById } from "@dokploy/server/services/compose";
|
||||
import type { findVolumeBackupById } from "@dokploy/server/services/volume-backups";
|
||||
import { normalizeS3Path } from "../backups/utils";
|
||||
import { getS3Credentials } from "../backups/utils";
|
||||
import { getS3Credentials, normalizeS3Path } from "../backups/utils";
|
||||
|
||||
export const backupVolume = async (
|
||||
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
|
||||
@@ -37,6 +36,9 @@ export const backupVolume = async (
|
||||
echo "Starting upload to S3..."
|
||||
${rcloneCommand}
|
||||
echo "Upload to S3 done ✅"
|
||||
echo "Cleaning up local backup file..."
|
||||
rm "${volumeBackupPath}/${backupFileName}"
|
||||
echo "Local backup file cleaned up ✅"
|
||||
`;
|
||||
|
||||
if (!turnOff) {
|
||||
|
||||
Reference in New Issue
Block a user