diff --git a/.circleci/config.yml b/.circleci/config.yml index c5e57a973..dd91309d3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -99,14 +99,14 @@ workflows: only: - main - canary - - fix/build-i18n + - 379-preview-deployment - build-arm64: filters: branches: only: - main - canary - - fix/build-i18n + - 379-preview-deployment - combine-manifests: requires: - build-amd64 @@ -116,4 +116,4 @@ workflows: only: - main - canary - - fix/build-i18n + - 379-preview-deployment diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9d1049c4..91bb70494 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -241,7 +241,7 @@ export function generate(schema: Schema): Template { - Use the same name of the folder as the id of the template. - The logo should be in the public folder. -- If you want to show a domain in the UI, please add the prefix \_HOST at the end of the variable name. +- If you want to show a domain in the UI, please add the `_HOST` suffix at the end of the variable name. - Test first on a vps or a server to make sure the template works. ## Docs & Website diff --git a/Dockerfile b/Dockerfile index 838fbe4f6..74b70db0e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,7 +35,6 @@ RUN apt-get update && apt-get install -y curl unzip apache2-utils && rm -rf /var COPY --from=build /prod/dokploy/.next ./.next COPY --from=build /prod/dokploy/dist ./dist COPY --from=build /prod/dokploy/next.config.mjs ./next.config.mjs -COPY --from=build /prod/dokploy/next-i18next.config.cjs ./next-i18next.config.cjs COPY --from=build /prod/dokploy/public ./public COPY --from=build /prod/dokploy/package.json ./package.json COPY --from=build /prod/dokploy/drizzle ./drizzle diff --git a/Dockerfile.cloud b/Dockerfile.cloud index 0f8427d46..020ea3d69 100644 --- a/Dockerfile.cloud +++ b/Dockerfile.cloud @@ -44,7 +44,6 @@ RUN apt-get update && apt-get install -y curl unzip apache2-utils && rm -rf /var COPY --from=build /prod/dokploy/.next ./.next COPY --from=build /prod/dokploy/dist ./dist COPY --from=build /prod/dokploy/next.config.mjs ./next.config.mjs -COPY --from=build /prod/dokploy/next-i18next.config.cjs ./next-i18next.config.cjs COPY --from=build /prod/dokploy/public ./public COPY --from=build /prod/dokploy/package.json ./package.json COPY --from=build /prod/dokploy/drizzle ./drizzle diff --git a/LICENSE.MD b/LICENSE.MD index 59e9d822e..8a508efb4 100644 --- a/LICENSE.MD +++ b/LICENSE.MD @@ -17,10 +17,10 @@ See the License for the specific language governing permissions and limitations ## Additional Terms for Specific Features -The following additional terms apply to the multi-node support, Docker Compose file and Multi Server features of Dokploy. In the event of a conflict, these provisions shall take precedence over those in the Apache License: +The following additional terms apply to the multi-node support, Docker Compose file, Preview Deployments and Multi Server features of Dokploy. In the event of a conflict, these provisions shall take precedence over those in the Apache License: -- **Self-Hosted Version Free**: All features of Dokploy, including multi-node support, Docker Compose file support and Multi Server, will always be free to use in the self-hosted version. -- **Restriction on Resale**: The multi-node support, Docker Compose file support and Multi Server features cannot be sold or offered as a service by any party other than the copyright holder without prior written consent. -- **Modification Distribution**: Any modifications to the multi-node support, Docker Compose file support and Multi Server features must be distributed freely and cannot be sold or offered as a service. +- **Self-Hosted Version Free**: All features of Dokploy, including multi-node support, Docker Compose file support, Preview Deployments and Multi Server, will always be free to use in the self-hosted version. +- **Restriction on Resale**: The multi-node support, Docker Compose file support, Preview Deployments and Multi Server features cannot be sold or offered as a service by any party other than the copyright holder without prior written consent. +- **Modification Distribution**: Any modifications to the multi-node support, Docker Compose file support, Preview Deployments and Multi Server features must be distributed freely and cannot be sold or offered as a service. For further inquiries or permissions, please contact us directly. diff --git a/apps/api/src/schema.ts b/apps/api/src/schema.ts index 5f26e0182..609289bf7 100644 --- a/apps/api/src/schema.ts +++ b/apps/api/src/schema.ts @@ -19,6 +19,16 @@ export const deployJobSchema = z.discriminatedUnion("applicationType", [ applicationType: z.literal("compose"), serverId: z.string().min(1), }), + z.object({ + applicationId: z.string(), + previewDeploymentId: z.string(), + titleLog: z.string(), + descriptionLog: z.string(), + server: z.boolean().optional(), + type: z.enum(["deploy"]), + applicationType: z.literal("application-preview"), + serverId: z.string().min(1), + }), ]); export type DeployJob = z.infer; diff --git a/apps/api/src/utils.ts b/apps/api/src/utils.ts index 2654487fe..d919f29e9 100644 --- a/apps/api/src/utils.ts +++ b/apps/api/src/utils.ts @@ -1,10 +1,12 @@ import { deployRemoteApplication, deployRemoteCompose, + deployRemotePreviewApplication, rebuildRemoteApplication, rebuildRemoteCompose, updateApplicationStatus, updateCompose, + updatePreviewDeployment, } from "@dokploy/server"; import type { DeployJob } from "./schema"; @@ -47,6 +49,20 @@ export const deploy = async (job: DeployJob) => { }); } } + } else if (job.applicationType === "application-preview") { + await updatePreviewDeployment(job.previewDeploymentId, { + previewStatus: "running", + }); + if (job.server) { + if (job.type === "deploy") { + await deployRemotePreviewApplication({ + applicationId: job.applicationId, + titleLog: job.titleLog, + descriptionLog: job.descriptionLog, + previewDeploymentId: job.previewDeploymentId, + }); + } + } } } catch (error) { if (job.applicationType === "application") { @@ -55,6 +71,10 @@ export const deploy = async (job: DeployJob) => { await updateCompose(job.composeId, { composeStatus: "error", }); + } else if (job.applicationType === "application-preview") { + await updatePreviewDeployment(job.previewDeploymentId, { + previewStatus: "error", + }); } } diff --git a/apps/dokploy/LICENSE.MD b/apps/dokploy/LICENSE.MD index 59e9d822e..8a508efb4 100644 --- a/apps/dokploy/LICENSE.MD +++ b/apps/dokploy/LICENSE.MD @@ -17,10 +17,10 @@ See the License for the specific language governing permissions and limitations ## Additional Terms for Specific Features -The following additional terms apply to the multi-node support, Docker Compose file and Multi Server features of Dokploy. In the event of a conflict, these provisions shall take precedence over those in the Apache License: +The following additional terms apply to the multi-node support, Docker Compose file, Preview Deployments and Multi Server features of Dokploy. In the event of a conflict, these provisions shall take precedence over those in the Apache License: -- **Self-Hosted Version Free**: All features of Dokploy, including multi-node support, Docker Compose file support and Multi Server, will always be free to use in the self-hosted version. -- **Restriction on Resale**: The multi-node support, Docker Compose file support and Multi Server features cannot be sold or offered as a service by any party other than the copyright holder without prior written consent. -- **Modification Distribution**: Any modifications to the multi-node support, Docker Compose file support and Multi Server features must be distributed freely and cannot be sold or offered as a service. +- **Self-Hosted Version Free**: All features of Dokploy, including multi-node support, Docker Compose file support, Preview Deployments and Multi Server, will always be free to use in the self-hosted version. +- **Restriction on Resale**: The multi-node support, Docker Compose file support, Preview Deployments and Multi Server features cannot be sold or offered as a service by any party other than the copyright holder without prior written consent. +- **Modification Distribution**: Any modifications to the multi-node support, Docker Compose file support, Preview Deployments and Multi Server features must be distributed freely and cannot be sold or offered as a service. For further inquiries or permissions, please contact us directly. diff --git a/apps/dokploy/__test__/compose/domain/labels.test.ts b/apps/dokploy/__test__/compose/domain/labels.test.ts index 8b5c2f9c4..8bc9fbccb 100644 --- a/apps/dokploy/__test__/compose/domain/labels.test.ts +++ b/apps/dokploy/__test__/compose/domain/labels.test.ts @@ -17,6 +17,7 @@ describe("createDomainLabels", () => { domainId: "", path: "/", createdAt: "", + previewDeploymentId: "", }; it("should create basic labels for web entrypoint", async () => { diff --git a/apps/dokploy/__test__/drop/drop.test.test.ts b/apps/dokploy/__test__/drop/drop.test.test.ts index 53ab02f2b..c4b2ba8d8 100644 --- a/apps/dokploy/__test__/drop/drop.test.test.ts +++ b/apps/dokploy/__test__/drop/drop.test.test.ts @@ -26,6 +26,7 @@ if (typeof window === "undefined") { const baseApp: ApplicationNested = { applicationId: "", + herokuVersion: "", applicationStatus: "done", appName: "", autoDeploy: true, @@ -33,6 +34,15 @@ const baseApp: ApplicationNested = { registryUrl: "", branch: null, dockerBuildStage: "", + isPreviewDeploymentsActive: false, + previewBuildArgs: null, + previewCertificateType: "none", + previewEnv: null, + previewHttps: false, + previewPath: "/", + previewPort: 3000, + previewLimit: 0, + previewWildcard: "", project: { env: "", adminId: "", diff --git a/apps/dokploy/__test__/traefik/traefik.test.ts b/apps/dokploy/__test__/traefik/traefik.test.ts index 7e11160bd..d05dda81d 100644 --- a/apps/dokploy/__test__/traefik/traefik.test.ts +++ b/apps/dokploy/__test__/traefik/traefik.test.ts @@ -6,6 +6,7 @@ import { expect, test } from "vitest"; const baseApp: ApplicationNested = { applicationId: "", + herokuVersion: "", applicationStatus: "done", appName: "", autoDeploy: true, @@ -14,6 +15,15 @@ const baseApp: ApplicationNested = { dockerBuildStage: "", registryUrl: "", buildArgs: null, + isPreviewDeploymentsActive: false, + previewBuildArgs: null, + previewCertificateType: "none", + previewEnv: null, + previewHttps: false, + previewPath: "/", + previewPort: 3000, + previewLimit: 0, + previewWildcard: "", project: { env: "", adminId: "", @@ -95,6 +105,7 @@ const baseDomain: Domain = { composeId: "", domainType: "application", uniqueConfigKey: 1, + previewDeploymentId: "", }; const baseRedirect: Redirect = { diff --git a/apps/dokploy/components/dashboard/application/advanced/volumes/add-volumes.tsx b/apps/dokploy/components/dashboard/application/advanced/volumes/add-volumes.tsx index d9dc16e70..5c6b95ca1 100644 --- a/apps/dokploy/components/dashboard/application/advanced/volumes/add-volumes.tsx +++ b/apps/dokploy/components/dashboard/application/advanced/volumes/add-volumes.tsx @@ -1,3 +1,4 @@ +import { CodeEditor } from "@/components/shared/code-editor"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -18,7 +19,6 @@ import { import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; -import { Textarea } from "@/components/ui/textarea"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -150,7 +150,7 @@ export const AddVolumes = ({ - + Volumes / Mounts @@ -303,9 +303,12 @@ export const AddVolumes = ({ Content -