Skip to content

Commit

Permalink
Merge pull request #359 from Dokploy/canary
Browse files Browse the repository at this point in the history
v0.7.0
  • Loading branch information
Siumauricio authored Aug 18, 2024
2 parents 385fbf4 + 38a75b0 commit 452793c
Show file tree
Hide file tree
Showing 53 changed files with 7,638 additions and 383 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ RUN curl -sSL https://nixpacks.com/install.sh -o install.sh \
&& pnpm install -g tsx

# Install buildpacks
RUN curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.35.0/pack-v0.35.0-linux.tgz" | tar -C /usr/local/bin/ --no-same-owner -xzv pack
COPY --from=buildpacksio/pack:0.35.0 /usr/local/bin/pack /usr/local/bin/pack

EXPOSE 3000
CMD [ "pnpm", "start" ]
89 changes: 89 additions & 0 deletions apps/dokploy/__test__/compose/domain/labels.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { Domain } from "@/server/api/services/domain";
import { createDomainLabels } from "@/server/utils/docker/domain";
import { describe, expect, it } from "vitest";

describe("createDomainLabels", () => {
const appName = "test-app";
const baseDomain: Domain = {
host: "example.com",
port: 8080,
https: false,
uniqueConfigKey: 1,
certificateType: "none",
applicationId: "",
composeId: "",
domainType: "compose",
serviceName: "test-app",
domainId: "",
path: "/",
createdAt: "",
};

it("should create basic labels for web entrypoint", async () => {
const labels = await createDomainLabels(appName, baseDomain, "web");
expect(labels).toEqual([
"traefik.http.routers.test-app-1-web.rule=Host(`example.com`)",
"traefik.http.routers.test-app-1-web.entrypoints=web",
"traefik.http.services.test-app-1-web.loadbalancer.server.port=8080",
"traefik.http.routers.test-app-1-web.service=test-app-1-web",
]);
});

it("should create labels for websecure entrypoint", async () => {
const labels = await createDomainLabels(appName, baseDomain, "websecure");
expect(labels).toEqual([
"traefik.http.routers.test-app-1-websecure.rule=Host(`example.com`)",
"traefik.http.routers.test-app-1-websecure.entrypoints=websecure",
"traefik.http.services.test-app-1-websecure.loadbalancer.server.port=8080",
"traefik.http.routers.test-app-1-websecure.service=test-app-1-websecure",
]);
});

it("should add redirect middleware for https on web entrypoint", async () => {
const httpsBaseDomain = { ...baseDomain, https: true };
const labels = await createDomainLabels(appName, httpsBaseDomain, "web");
expect(labels).toContain(
"traefik.http.routers.test-app-1-web.middlewares=redirect-to-https@file",
);
});

it("should add Let's Encrypt configuration for websecure with letsencrypt certificate", async () => {
const letsencryptDomain = {
...baseDomain,
https: true,
certificateType: "letsencrypt" as const,
};
const labels = await createDomainLabels(
appName,
letsencryptDomain,
"websecure",
);
expect(labels).toContain(
"traefik.http.routers.test-app-1-websecure.tls.certresolver=letsencrypt",
);
});

it("should not add Let's Encrypt configuration for non-letsencrypt certificate", async () => {
const nonLetsencryptDomain = {
...baseDomain,
https: true,
certificateType: "none" as const,
};
const labels = await createDomainLabels(
appName,
nonLetsencryptDomain,
"websecure",
);
expect(labels).not.toContain(
"traefik.http.routers.test-app-1-websecure.tls.certresolver=letsencrypt",
);
});

it("should handle different ports correctly", async () => {
const customPortDomain = { ...baseDomain, port: 3000 };
const labels = await createDomainLabels(appName, customPortDomain, "web");
expect(labels).toContain(
"traefik.http.services.test-app-1-web.loadbalancer.server.port=3000",
);
});
});
29 changes: 29 additions & 0 deletions apps/dokploy/__test__/compose/domain/network-root.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { addDokployNetworkToRoot } from "@/server/utils/docker/domain";
import { describe, expect, it } from "vitest";

describe("addDokployNetworkToRoot", () => {
it("should create network object if networks is undefined", () => {
const result = addDokployNetworkToRoot(undefined);
expect(result).toEqual({ "dokploy-network": { external: true } });
});

it("should add network to an empty object", () => {
const result = addDokployNetworkToRoot({});
expect(result).toEqual({ "dokploy-network": { external: true } });
});

it("should not modify existing network configuration", () => {
const existing = { "dokploy-network": { external: false } };
const result = addDokployNetworkToRoot(existing);
expect(result).toEqual({ "dokploy-network": { external: true } });
});

it("should add network alongside existing networks", () => {
const existing = { "other-network": { external: true } };
const result = addDokployNetworkToRoot(existing);
expect(result).toEqual({
"other-network": { external: true },
"dokploy-network": { external: true },
});
});
});
24 changes: 24 additions & 0 deletions apps/dokploy/__test__/compose/domain/network-service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { addDokployNetworkToService } from "@/server/utils/docker/domain";
import { describe, expect, it } from "vitest";

describe("addDokployNetworkToService", () => {
it("should add network to an empty array", () => {
const result = addDokployNetworkToService([]);
expect(result).toEqual(["dokploy-network"]);
});

it("should not add duplicate network to an array", () => {
const result = addDokployNetworkToService(["dokploy-network"]);
expect(result).toEqual(["dokploy-network"]);
});

it("should add network to an existing array with other networks", () => {
const result = addDokployNetworkToService(["other-network"]);
expect(result).toEqual(["other-network", "dokploy-network"]);
});

it("should add network to an object if networks is an object", () => {
const result = addDokployNetworkToService({ "other-network": {} });
expect(result).toEqual({ "other-network": {}, "dokploy-network": {} });
});
});
3 changes: 3 additions & 0 deletions apps/dokploy/__test__/traefik/traefik.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ const baseDomain: Domain = {
https: false,
path: null,
port: null,
serviceName: "",
composeId: "",
domainType: "application",
uniqueConfigKey: 1,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { PlusIcon } from "lucide-react";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
Expand All @@ -52,6 +52,7 @@ export const AddPort = ({
applicationId,
children = <PlusIcon className="h-4 w-4" />,
}: Props) => {
const [isOpen, setIsOpen] = useState(false);
const utils = api.useUtils();

const { mutateAsync, isLoading, error, isError } =
Expand Down Expand Up @@ -82,14 +83,15 @@ export const AddPort = ({
await utils.application.one.invalidate({
applicationId,
});
setIsOpen(false);
})
.catch(() => {
toast.error("Error to create the port");
});
};

return (
<Dialog>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button>{children}</Button>
</DialogTrigger>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { PenBoxIcon, Pencil } from "lucide-react";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
Expand All @@ -49,6 +49,7 @@ interface Props {
}

export const UpdatePort = ({ portId }: Props) => {
const [isOpen, setIsOpen] = useState(false);
const utils = api.useUtils();
const { data } = api.port.one.useQuery(
{
Expand Down Expand Up @@ -89,14 +90,15 @@ export const UpdatePort = ({ portId }: Props) => {
await utils.application.one.invalidate({
applicationId: response?.applicationId,
});
setIsOpen(false);
})
.catch(() => {
toast.error("Error to update the port");
});
};

return (
<Dialog>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button variant="ghost" isLoading={isLoading}>
<PenBoxIcon className="size-4 text-muted-foreground" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Switch } from "@/components/ui/switch";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { PlusIcon } from "lucide-react";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
Expand All @@ -45,6 +45,7 @@ export const AddRedirect = ({
applicationId,
children = <PlusIcon className="h-4 w-4" />,
}: Props) => {
const [isOpen, setIsOpen] = useState(false);
const utils = api.useUtils();

const { mutateAsync, isLoading, error, isError } =
Expand Down Expand Up @@ -80,14 +81,15 @@ export const AddRedirect = ({
await utils.application.readTraefikConfig.invalidate({
applicationId,
});
setIsOpen(false);
})
.catch(() => {
toast.error("Error to create the redirect");
});
};

return (
<Dialog>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button>{children}</Button>
</DialogTrigger>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Switch } from "@/components/ui/switch";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { PenBoxIcon, Pencil } from "lucide-react";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
Expand All @@ -41,6 +41,7 @@ interface Props {

export const UpdateRedirect = ({ redirectId }: Props) => {
const utils = api.useUtils();
const [isOpen, setIsOpen] = useState(false);
const { data } = api.redirects.one.useQuery(
{
redirectId,
Expand Down Expand Up @@ -84,14 +85,15 @@ export const UpdateRedirect = ({ redirectId }: Props) => {
await utils.application.one.invalidate({
applicationId: response?.applicationId,
});
setIsOpen(false);
})
.catch(() => {
toast.error("Error to update the redirect");
});
};

return (
<Dialog>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button variant="ghost" isLoading={isLoading}>
<PenBoxIcon className="size-4 text-muted-foreground" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { Input } from "@/components/ui/input";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { PlusIcon } from "lucide-react";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
Expand All @@ -43,7 +43,7 @@ export const AddSecurity = ({
children = <PlusIcon className="h-4 w-4" />,
}: Props) => {
const utils = api.useUtils();

const [isOpen, setIsOpen] = useState(false);
const { mutateAsync, isLoading, error, isError } =
api.security.create.useMutation();

Expand Down Expand Up @@ -72,14 +72,15 @@ export const AddSecurity = ({
await utils.application.readTraefikConfig.invalidate({
applicationId,
});
setIsOpen(false);
})
.catch(() => {
toast.error("Error to create the security");
});
};

return (
<Dialog>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button>{children}</Button>
</DialogTrigger>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { Input } from "@/components/ui/input";
import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { PenBoxIcon, Pencil } from "lucide-react";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
Expand All @@ -38,6 +38,7 @@ interface Props {
}

export const UpdateSecurity = ({ securityId }: Props) => {
const [isOpen, setIsOpen] = useState(false);
const utils = api.useUtils();
const { data } = api.security.one.useQuery(
{
Expand Down Expand Up @@ -79,14 +80,15 @@ export const UpdateSecurity = ({ securityId }: Props) => {
await utils.application.one.invalidate({
applicationId: response?.applicationId,
});
setIsOpen(false);
})
.catch(() => {
toast.error("Error to update the security");
});
};

return (
<Dialog>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button variant="ghost" isLoading={isLoading}>
<PenBoxIcon className="size-4 text-muted-foreground" />
Expand Down
Loading

0 comments on commit 452793c

Please sign in to comment.