mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat: add preview deployments #379
This commit is contained in:
@@ -22,9 +22,10 @@ import { redirects } from "./redirects";
|
||||
import { registry } from "./registry";
|
||||
import { security } from "./security";
|
||||
import { server } from "./server";
|
||||
import { applicationStatus } from "./shared";
|
||||
import { applicationStatus, certificateType } from "./shared";
|
||||
import { sshKeys } from "./ssh-key";
|
||||
import { generateAppName } from "./utils";
|
||||
import { previewDeployments } from "./preview-deployments";
|
||||
|
||||
export const sourceType = pgEnum("sourceType", [
|
||||
"docker",
|
||||
@@ -114,6 +115,19 @@ export const applications = pgTable("application", {
|
||||
.unique(),
|
||||
description: text("description"),
|
||||
env: text("env"),
|
||||
previewEnv: text("previewEnv"),
|
||||
previewBuildArgs: text("previewBuildArgs"),
|
||||
previewWildcard: text("previewWildcard"),
|
||||
previewPort: integer("previewPort").default(3000),
|
||||
previewHttps: boolean("previewHttps").notNull().default(false),
|
||||
previewPath: text("previewPath").default("/"),
|
||||
previewCertificateType: certificateType("certificateType")
|
||||
.notNull()
|
||||
.default("none"),
|
||||
previewLimit: integer("previewLimit").default(3),
|
||||
isPreviewDeploymentsActive: boolean("isPreviewDeploymentsActive").default(
|
||||
false,
|
||||
),
|
||||
buildArgs: text("buildArgs"),
|
||||
memoryReservation: integer("memoryReservation"),
|
||||
memoryLimit: integer("memoryLimit"),
|
||||
@@ -239,6 +253,7 @@ export const applicationsRelations = relations(
|
||||
fields: [applications.serverId],
|
||||
references: [server.serverId],
|
||||
}),
|
||||
previewDeployments: many(previewDeployments),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -348,6 +363,7 @@ const createSchema = createInsertSchema(applications, {
|
||||
subtitle: z.string().optional(),
|
||||
dockerImage: z.string().optional(),
|
||||
username: z.string().optional(),
|
||||
isPreviewDeploymentsActive: z.boolean().optional(),
|
||||
password: z.string().optional(),
|
||||
registryUrl: z.string().optional(),
|
||||
customGitSSHKeyId: z.string().optional(),
|
||||
@@ -378,6 +394,14 @@ const createSchema = createInsertSchema(applications, {
|
||||
modeSwarm: ServiceModeSwarmSchema.nullable(),
|
||||
labelsSwarm: LabelsSwarmSchema.nullable(),
|
||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||
previewPort: z.number().optional(),
|
||||
previewEnv: z.string().optional(),
|
||||
previewBuildArgs: z.string().optional(),
|
||||
previewWildcard: z.string().optional(),
|
||||
previewLimit: z.number().optional(),
|
||||
previewHttps: z.boolean().optional(),
|
||||
previewPath: z.string().optional(),
|
||||
previewCertificateType: z.enum(["letsencrypt", "none"]).optional(),
|
||||
});
|
||||
|
||||
export const apiCreateApplication = createSchema.pick({
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import { pgEnum, pgTable, text } from "drizzle-orm/pg-core";
|
||||
import { is, relations } from "drizzle-orm";
|
||||
import {
|
||||
type AnyPgColumn,
|
||||
boolean,
|
||||
pgEnum,
|
||||
pgTable,
|
||||
text,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import { applications } from "./application";
|
||||
import { compose } from "./compose";
|
||||
import { server } from "./server";
|
||||
import { previewDeployments } from "./preview-deployments";
|
||||
|
||||
export const deploymentStatus = pgEnum("deploymentStatus", [
|
||||
"running",
|
||||
@@ -32,6 +39,11 @@ export const deployments = pgTable("deployment", {
|
||||
serverId: text("serverId").references(() => server.serverId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
isPreviewDeployment: boolean("isPreviewDeployment").default(false),
|
||||
previewDeploymentId: text("previewDeploymentId").references(
|
||||
(): AnyPgColumn => previewDeployments.previewDeploymentId,
|
||||
{ onDelete: "cascade" },
|
||||
),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString()),
|
||||
@@ -50,6 +62,10 @@ export const deploymentsRelations = relations(deployments, ({ one }) => ({
|
||||
fields: [deployments.serverId],
|
||||
references: [server.serverId],
|
||||
}),
|
||||
previewDeployment: one(previewDeployments, {
|
||||
fields: [deployments.previewDeploymentId],
|
||||
references: [previewDeployments.previewDeploymentId],
|
||||
}),
|
||||
}));
|
||||
|
||||
const schema = createInsertSchema(deployments, {
|
||||
@@ -59,6 +75,7 @@ const schema = createInsertSchema(deployments, {
|
||||
applicationId: z.string(),
|
||||
composeId: z.string(),
|
||||
description: z.string().optional(),
|
||||
previewDeploymentId: z.string(),
|
||||
});
|
||||
|
||||
export const apiCreateDeployment = schema
|
||||
@@ -68,11 +85,24 @@ export const apiCreateDeployment = schema
|
||||
logPath: true,
|
||||
applicationId: true,
|
||||
description: true,
|
||||
previewDeploymentId: true,
|
||||
})
|
||||
.extend({
|
||||
applicationId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiCreateDeploymentPreview = schema
|
||||
.pick({
|
||||
title: true,
|
||||
status: true,
|
||||
logPath: true,
|
||||
description: true,
|
||||
previewDeploymentId: true,
|
||||
})
|
||||
.extend({
|
||||
previewDeploymentId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiCreateDeploymentCompose = schema
|
||||
.pick({
|
||||
title: true,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import {
|
||||
type AnyPgColumn,
|
||||
boolean,
|
||||
integer,
|
||||
pgEnum,
|
||||
@@ -14,8 +15,13 @@ import { domain } from "../validations/domain";
|
||||
import { applications } from "./application";
|
||||
import { compose } from "./compose";
|
||||
import { certificateType } from "./shared";
|
||||
import { previewDeployments } from "./preview-deployments";
|
||||
|
||||
export const domainType = pgEnum("domainType", ["compose", "application"]);
|
||||
export const domainType = pgEnum("domainType", [
|
||||
"compose",
|
||||
"application",
|
||||
"preview",
|
||||
]);
|
||||
|
||||
export const domains = pgTable("domain", {
|
||||
domainId: text("domainId")
|
||||
@@ -28,6 +34,7 @@ export const domains = pgTable("domain", {
|
||||
path: text("path").default("/"),
|
||||
serviceName: text("serviceName"),
|
||||
domainType: domainType("domainType").default("application"),
|
||||
isPreviewDeployment: boolean("isPreviewDeployment").default(false), // TODO: remove
|
||||
uniqueConfigKey: serial("uniqueConfigKey"),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
@@ -39,6 +46,10 @@ export const domains = pgTable("domain", {
|
||||
() => applications.applicationId,
|
||||
{ onDelete: "cascade" },
|
||||
),
|
||||
previewDeploymentId: text("previewDeploymentId").references(
|
||||
(): AnyPgColumn => previewDeployments.previewDeploymentId,
|
||||
{ onDelete: "cascade" },
|
||||
),
|
||||
certificateType: certificateType("certificateType").notNull().default("none"),
|
||||
});
|
||||
|
||||
@@ -51,6 +62,10 @@ export const domainsRelations = relations(domains, ({ one }) => ({
|
||||
fields: [domains.composeId],
|
||||
references: [compose.composeId],
|
||||
}),
|
||||
previewDeployment: one(previewDeployments, {
|
||||
fields: [domains.previewDeploymentId],
|
||||
references: [previewDeployments.previewDeploymentId],
|
||||
}),
|
||||
}));
|
||||
|
||||
const createSchema = createInsertSchema(domains, domain._def.schema.shape);
|
||||
@@ -65,6 +80,7 @@ export const apiCreateDomain = createSchema.pick({
|
||||
composeId: true,
|
||||
serviceName: true,
|
||||
domainType: true,
|
||||
previewDeploymentId: true,
|
||||
});
|
||||
|
||||
export const apiFindDomain = createSchema
|
||||
|
||||
@@ -29,3 +29,4 @@ export * from "./github";
|
||||
export * from "./gitlab";
|
||||
export * from "./server";
|
||||
export * from "./utils";
|
||||
export * from "./preview-deployments";
|
||||
74
packages/server/src/db/schema/preview-deployments.ts
Normal file
74
packages/server/src/db/schema/preview-deployments.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import { pgTable, text } from "drizzle-orm/pg-core";
|
||||
import { nanoid } from "nanoid";
|
||||
import { applications } from "./application";
|
||||
import { domains } from "./domain";
|
||||
import { deployments } from "./deployment";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { z } from "zod";
|
||||
import { generateAppName } from "./utils";
|
||||
import { applicationStatus } from "./shared";
|
||||
|
||||
export const previewDeployments = pgTable("preview_deployments", {
|
||||
previewDeploymentId: text("previewDeploymentId")
|
||||
.notNull()
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
branch: text("branch").notNull(),
|
||||
pullRequestId: text("pullRequestId").notNull(),
|
||||
pullRequestNumber: text("pullRequestNumber").notNull(),
|
||||
pullRequestURL: text("pullRequestURL").notNull(),
|
||||
pullRequestTitle: text("pullRequestTitle").notNull(),
|
||||
pullRequestCommentId: text("pullRequestCommentId").notNull(),
|
||||
previewStatus: applicationStatus("previewStatus").notNull().default("idle"),
|
||||
appName: text("appName")
|
||||
.notNull()
|
||||
.$defaultFn(() => generateAppName("preview"))
|
||||
.unique(),
|
||||
applicationId: text("applicationId")
|
||||
.notNull()
|
||||
.references(() => applications.applicationId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
domainId: text("domainId").references(() => domains.domainId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString()),
|
||||
expiresAt: text("expiresAt"),
|
||||
});
|
||||
|
||||
export const previewDeploymentsRelations = relations(
|
||||
previewDeployments,
|
||||
({ one, many }) => ({
|
||||
deployments: many(deployments),
|
||||
domain: one(domains, {
|
||||
fields: [previewDeployments.domainId],
|
||||
references: [domains.domainId],
|
||||
}),
|
||||
application: one(applications, {
|
||||
fields: [previewDeployments.applicationId],
|
||||
references: [applications.applicationId],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
export const createSchema = createInsertSchema(previewDeployments, {
|
||||
applicationId: z.string(),
|
||||
});
|
||||
|
||||
export const apiCreatePreviewDeployment = createSchema
|
||||
.pick({
|
||||
applicationId: true,
|
||||
domainId: true,
|
||||
branch: true,
|
||||
pullRequestId: true,
|
||||
pullRequestNumber: true,
|
||||
pullRequestURL: true,
|
||||
pullRequestTitle: true,
|
||||
})
|
||||
.extend({
|
||||
applicationId: z.string().min(1),
|
||||
// deploymentId: z.string().min(1),
|
||||
});
|
||||
Reference in New Issue
Block a user