Merge pull request #25 from Dokploy/canary

Main release
This commit is contained in:
Mauricio Siu
2024-05-01 21:40:40 -06:00
committed by GitHub
53 changed files with 575 additions and 298 deletions

5
.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
node_modules
.git
.gitignore
*.md
dist

3
.env.production.example Normal file
View File

@@ -0,0 +1,3 @@
DATABASE_URL="postgres://dokploy:amukds4wi9001583845717ad2@dokploy-postgres:5432/dokploy"
PORT=3000
NODE_ENV=production

View File

@@ -3,8 +3,15 @@ on:
pull_request: pull_request:
branches: branches:
- main - main
- canary
push:
branches:
- main
- canary
jobs: jobs:
build: build-app:
if: github.event_name == 'pull_request'
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
@@ -22,4 +29,53 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: pnpm install run: pnpm install
- name: Run Build - name: Run Build
run: pnpm build run: pnpm build
build-docker-on-pr:
if: github.event_name == 'pull_request'
needs: build-app
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Prepare .env file
run: |
cp .env.production.example .env.production
- name: Run custom Docker build script
run: |
chmod +x ./docker/build.sh
echo "Building Docker image for ${{ github.base_ref }}"
./docker/build.sh ${{ github.base_ref == 'canary' && 'canary' || '' }}
build-and-push-docker-on-push:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Prepare .env file
run: |
cp .env.production.example .env.production
- name: Build and push Docker image using custom script
run: |
chmod +x ./docker/build.sh
chmod +x ./docker/push.sh
./docker/build.sh ${{ github.ref_name == 'canary' && 'canary' || '' }}
./docker/push.sh ${{ github.ref_name == 'canary' && 'canary' || '' }}

2
.gitignore vendored
View File

@@ -6,6 +6,8 @@
.pnp.js .pnp.js
/redis-data /redis-data
traefik.yml traefik.yml
.docker
.env.production
# testing # testing
/coverage /coverage

View File

@@ -49,12 +49,16 @@ feat: add new feature
``` ```
## Setup ## Setup
Before you start, please make the clone based on the `canary` branch, since the `main` branch is the source of truth and should always reflect the latest stable release, also the PRs will be merged to the `canary` branch.
```bash ```bash
git clone https://github.com/dokploy/dokploy.git git clone https://github.com/dokploy/dokploy.git
cd dokploy cd dokploy
npm install pnpm install
cp .env.example .env cp .env.example .env
``` ```
@@ -62,28 +66,40 @@ cp .env.example .env
Is required to have **Docker** installed on your machine. Is required to have **Docker** installed on your machine.
### Setup
Run the command that will spin up all the required services and files.
```bash ```bash
npm run dev pnpm run setup
``` ```
Now run the development server.
```bash
pnpm run dev
```
Go to http://localhost:3000 to see the development server Go to http://localhost:3000 to see the development server
## Build ## Build
```bash ```bash
npm run build pnpm run build
``` ```
## Docker ## Docker
To build the docker image To build the docker image
```bash ```bash
npm run docker:build pnpm run docker:build
``` ```
To push the docker image To push the docker image
```bash ```bash
npm run docker:push pnpm run docker:push
``` ```
## Password Reset ## Password Reset

View File

@@ -65,7 +65,7 @@ export const Login2FA = ({ authId }: Props) => {
duration: 2000, duration: 2000,
}); });
push("/dashboard"); push("/dashboard/projects");
}) })
.catch(() => { .catch(() => {
toast.error("Signin failed", { toast.error("Signin failed", {

View File

@@ -21,19 +21,19 @@ import { api } from "@/utils/api";
import { toast } from "sonner"; import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({ const addEnvironmentSchema = z.object({
enviroment: z.string(), environment: z.string(),
}); });
type EnviromentSchema = z.infer<typeof addEnviromentSchema>; type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props { interface Props {
applicationId: string; applicationId: string;
} }
export const ShowEnviroment = ({ applicationId }: Props) => { export const ShowEnvironment = ({ applicationId }: Props) => {
const { mutateAsync, isLoading } = const { mutateAsync, isLoading } =
api.application.saveEnviroment.useMutation(); api.application.saveEnvironment.useMutation();
const { data, refetch } = api.application.one.useQuery( const { data, refetch } = api.application.one.useQuery(
{ {
@@ -43,32 +43,32 @@ export const ShowEnviroment = ({ applicationId }: Props) => {
enabled: !!applicationId, enabled: !!applicationId,
}, },
); );
const form = useForm<EnviromentSchema>({ const form = useForm<EnvironmentSchema>({
defaultValues: { defaultValues: {
enviroment: "", environment: "",
}, },
resolver: zodResolver(addEnviromentSchema), resolver: zodResolver(addEnvironmentSchema),
}); });
useEffect(() => { useEffect(() => {
if (data) { if (data) {
form.reset({ form.reset({
enviroment: data.env || "", environment: data.env || "",
}); });
} }
}, [form.reset, data, form]); }, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => { const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({ mutateAsync({
env: data.enviroment, env: data.environment,
applicationId, applicationId,
}) })
.then(async () => { .then(async () => {
toast.success("Enviroments Added"); toast.success("Environments Added");
await refetch(); await refetch();
}) })
.catch(() => { .catch(() => {
toast.error("Error to add enviroment"); toast.error("Error to add environment");
}); });
}; };
@@ -76,9 +76,9 @@ export const ShowEnviroment = ({ applicationId }: Props) => {
<div className="flex w-full flex-col gap-5 "> <div className="flex w-full flex-col gap-5 ">
<Card className="bg-background"> <Card className="bg-background">
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle> <CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription> <CardDescription>
You can add enviroment variables to your resource. You can add environment variables to your resource.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -90,7 +90,7 @@ export const ShowEnviroment = ({ applicationId }: Props) => {
> >
<FormField <FormField
control={form.control} control={form.control}
name="enviroment" name="environment"
render={({ field }) => ( render={({ field }) => (
<FormItem className="w-full"> <FormItem className="w-full">
<FormControl> <FormControl>

View File

@@ -21,18 +21,18 @@ import { api } from "@/utils/api";
import { toast } from "sonner"; import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({ const addEnvironmentSchema = z.object({
enviroment: z.string(), environment: z.string(),
}); });
type EnviromentSchema = z.infer<typeof addEnviromentSchema>; type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props { interface Props {
mariadbId: string; mariadbId: string;
} }
export const ShowMariadbEnviroment = ({ mariadbId }: Props) => { export const ShowMariadbEnvironment = ({ mariadbId }: Props) => {
const { mutateAsync, isLoading } = api.mariadb.saveEnviroment.useMutation(); const { mutateAsync, isLoading } = api.mariadb.saveEnvironment.useMutation();
const { data, refetch } = api.mariadb.one.useQuery( const { data, refetch } = api.mariadb.one.useQuery(
{ {
@@ -42,32 +42,32 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => {
enabled: !!mariadbId, enabled: !!mariadbId,
}, },
); );
const form = useForm<EnviromentSchema>({ const form = useForm<EnvironmentSchema>({
defaultValues: { defaultValues: {
enviroment: "", environment: "",
}, },
resolver: zodResolver(addEnviromentSchema), resolver: zodResolver(addEnvironmentSchema),
}); });
useEffect(() => { useEffect(() => {
if (data) { if (data) {
form.reset({ form.reset({
enviroment: data.env || "", environment: data.env || "",
}); });
} }
}, [form.reset, data, form]); }, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => { const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({ mutateAsync({
env: data.enviroment, env: data.environment,
mariadbId, mariadbId,
}) })
.then(async () => { .then(async () => {
toast.success("Enviroments Added"); toast.success("Environments Added");
await refetch(); await refetch();
}) })
.catch(() => { .catch(() => {
toast.error("Error to add enviroment"); toast.error("Error to add environment");
}); });
}; };
@@ -75,9 +75,9 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => {
<div className="flex w-full flex-col gap-5 "> <div className="flex w-full flex-col gap-5 ">
<Card className="bg-background"> <Card className="bg-background">
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle> <CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription> <CardDescription>
You can add enviroment variables to your database. You can add environment variables to your database.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -89,7 +89,7 @@ export const ShowMariadbEnviroment = ({ mariadbId }: Props) => {
> >
<FormField <FormField
control={form.control} control={form.control}
name="enviroment" name="environment"
render={({ field }) => ( render={({ field }) => (
<FormItem className="w-full"> <FormItem className="w-full">
<FormControl> <FormControl>

View File

@@ -21,18 +21,18 @@ import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
const addEnviromentSchema = z.object({ const addEnvironmentSchema = z.object({
enviroment: z.string(), environment: z.string(),
}); });
type EnviromentSchema = z.infer<typeof addEnviromentSchema>; type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props { interface Props {
mongoId: string; mongoId: string;
} }
export const ShowMongoEnviroment = ({ mongoId }: Props) => { export const ShowMongoEnvironment = ({ mongoId }: Props) => {
const { mutateAsync, isLoading } = api.mongo.saveEnviroment.useMutation(); const { mutateAsync, isLoading } = api.mongo.saveEnvironment.useMutation();
const { data, refetch } = api.mongo.one.useQuery( const { data, refetch } = api.mongo.one.useQuery(
{ {
@@ -42,32 +42,32 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => {
enabled: !!mongoId, enabled: !!mongoId,
}, },
); );
const form = useForm<EnviromentSchema>({ const form = useForm<EnvironmentSchema>({
defaultValues: { defaultValues: {
enviroment: "", environment: "",
}, },
resolver: zodResolver(addEnviromentSchema), resolver: zodResolver(addEnvironmentSchema),
}); });
useEffect(() => { useEffect(() => {
if (data) { if (data) {
form.reset({ form.reset({
enviroment: data.env || "", environment: data.env || "",
}); });
} }
}, [form.reset, data, form]); }, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => { const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({ mutateAsync({
env: data.enviroment, env: data.environment,
mongoId, mongoId,
}) })
.then(async () => { .then(async () => {
toast.success("Enviroments Added"); toast.success("Environments Added");
await refetch(); await refetch();
}) })
.catch(() => { .catch(() => {
toast.error("Error to add enviroment"); toast.error("Error to add environment");
}); });
}; };
@@ -75,9 +75,9 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => {
<div className="flex w-full flex-col gap-5 "> <div className="flex w-full flex-col gap-5 ">
<Card className="bg-background"> <Card className="bg-background">
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle> <CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription> <CardDescription>
You can add enviroment variables to your database. You can add environment variables to your database.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -89,7 +89,7 @@ export const ShowMongoEnviroment = ({ mongoId }: Props) => {
> >
<FormField <FormField
control={form.control} control={form.control}
name="enviroment" name="environment"
render={({ field }) => ( render={({ field }) => (
<FormItem className="w-full"> <FormItem className="w-full">
<FormControl> <FormControl>

View File

@@ -21,18 +21,18 @@ import { api } from "@/utils/api";
import { toast } from "sonner"; import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({ const addEnvironmentSchema = z.object({
enviroment: z.string(), environment: z.string(),
}); });
type EnviromentSchema = z.infer<typeof addEnviromentSchema>; type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props { interface Props {
mysqlId: string; mysqlId: string;
} }
export const ShowMysqlEnviroment = ({ mysqlId }: Props) => { export const ShowMysqlEnvironment = ({ mysqlId }: Props) => {
const { mutateAsync, isLoading } = api.mysql.saveEnviroment.useMutation(); const { mutateAsync, isLoading } = api.mysql.saveEnvironment.useMutation();
const { data, refetch } = api.mysql.one.useQuery( const { data, refetch } = api.mysql.one.useQuery(
{ {
@@ -42,32 +42,32 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => {
enabled: !!mysqlId, enabled: !!mysqlId,
}, },
); );
const form = useForm<EnviromentSchema>({ const form = useForm<EnvironmentSchema>({
defaultValues: { defaultValues: {
enviroment: "", environment: "",
}, },
resolver: zodResolver(addEnviromentSchema), resolver: zodResolver(addEnvironmentSchema),
}); });
useEffect(() => { useEffect(() => {
if (data) { if (data) {
form.reset({ form.reset({
enviroment: data.env || "", environment: data.env || "",
}); });
} }
}, [form.reset, data, form]); }, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => { const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({ mutateAsync({
env: data.enviroment, env: data.environment,
mysqlId, mysqlId,
}) })
.then(async () => { .then(async () => {
toast.success("Enviroments Added"); toast.success("Environments Added");
await refetch(); await refetch();
}) })
.catch(() => { .catch(() => {
toast.error("Error to add enviroment"); toast.error("Error to add environment");
}); });
}; };
@@ -75,9 +75,9 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => {
<div className="flex w-full flex-col gap-5 "> <div className="flex w-full flex-col gap-5 ">
<Card className="bg-background"> <Card className="bg-background">
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle> <CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription> <CardDescription>
You can add enviroment variables to your database. You can add environment variables to your database.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -89,7 +89,7 @@ export const ShowMysqlEnviroment = ({ mysqlId }: Props) => {
> >
<FormField <FormField
control={form.control} control={form.control}
name="enviroment" name="environment"
render={({ field }) => ( render={({ field }) => (
<FormItem className="w-full"> <FormItem className="w-full">
<FormControl> <FormControl>

View File

@@ -21,18 +21,18 @@ import { api } from "@/utils/api";
import { toast } from "sonner"; import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({ const addEnvironmentSchema = z.object({
enviroment: z.string(), environment: z.string(),
}); });
type EnviromentSchema = z.infer<typeof addEnviromentSchema>; type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props { interface Props {
postgresId: string; postgresId: string;
} }
export const ShowPostgresEnviroment = ({ postgresId }: Props) => { export const ShowPostgresEnvironment = ({ postgresId }: Props) => {
const { mutateAsync, isLoading } = api.postgres.saveEnviroment.useMutation(); const { mutateAsync, isLoading } = api.postgres.saveEnvironment.useMutation();
const { data, refetch } = api.postgres.one.useQuery( const { data, refetch } = api.postgres.one.useQuery(
{ {
@@ -42,32 +42,32 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => {
enabled: !!postgresId, enabled: !!postgresId,
}, },
); );
const form = useForm<EnviromentSchema>({ const form = useForm<EnvironmentSchema>({
defaultValues: { defaultValues: {
enviroment: "", environment: "",
}, },
resolver: zodResolver(addEnviromentSchema), resolver: zodResolver(addEnvironmentSchema),
}); });
useEffect(() => { useEffect(() => {
if (data) { if (data) {
form.reset({ form.reset({
enviroment: data.env || "", environment: data.env || "",
}); });
} }
}, [form.reset, data, form]); }, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => { const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({ mutateAsync({
env: data.enviroment, env: data.environment,
postgresId, postgresId,
}) })
.then(async () => { .then(async () => {
toast.success("Enviroments Added"); toast.success("Environments Added");
await refetch(); await refetch();
}) })
.catch(() => { .catch(() => {
toast.error("Error to add enviroment"); toast.error("Error to add environment");
}); });
}; };
@@ -75,9 +75,9 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => {
<div className="flex w-full flex-col gap-5 "> <div className="flex w-full flex-col gap-5 ">
<Card className="bg-background"> <Card className="bg-background">
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle> <CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription> <CardDescription>
You can add enviroment variables to your database. You can add environment variables to your database.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -89,7 +89,7 @@ export const ShowPostgresEnviroment = ({ postgresId }: Props) => {
> >
<FormField <FormField
control={form.control} control={form.control}
name="enviroment" name="environment"
render={({ field }) => ( render={({ field }) => (
<FormItem className="w-full"> <FormItem className="w-full">
<FormControl> <FormControl>

View File

@@ -21,7 +21,8 @@ import { Textarea } from "@/components/ui/textarea";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { AlertTriangle, PlusIcon } from "lucide-react"; import { AlertTriangle, PlusIcon } from "lucide-react";
import { useEffect } from "react"; import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { toast } from "sonner"; import { toast } from "sonner";
import { z } from "zod"; import { z } from "zod";
@@ -37,10 +38,9 @@ type AddProject = z.infer<typeof AddProjectSchema>;
export const AddProject = () => { export const AddProject = () => {
const utils = api.useUtils(); const utils = api.useUtils();
const [isOpen, setIsOpen] = useState(false);
const { mutateAsync, isLoading, error, isError } = const { mutateAsync, error, isError } = api.project.create.useMutation();
api.project.create.useMutation(); const router = useRouter();
const form = useForm<AddProject>({ const form = useForm<AddProject>({
defaultValues: { defaultValues: {
description: "", description: "",
@@ -61,16 +61,19 @@ export const AddProject = () => {
name: data.name, name: data.name,
description: data.description, description: data.description,
}) })
.then(async () => { .then(async (data) => {
toast.success("Project Created");
await utils.project.all.invalidate(); await utils.project.all.invalidate();
toast.success("Project Created");
setIsOpen(false);
router.push(`/dashboard/project/${data.projectId}`);
}) })
.catch(() => { .catch(() => {
toast.error("Error to create a project"); toast.error("Error to create a project");
}); });
}; };
return ( return (
<Dialog> <Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button> <Button>
<PlusIcon className="h-4 w-4" /> <PlusIcon className="h-4 w-4" />
@@ -134,7 +137,7 @@ export const AddProject = () => {
<DialogFooter> <DialogFooter>
<Button <Button
isLoading={isLoading} isLoading={form.formState.isSubmitting}
form="hook-form-add-project" form="hook-form-add-project"
type="submit" type="submit"
> >

View File

@@ -21,18 +21,18 @@ import { api } from "@/utils/api";
import { toast } from "sonner"; import { toast } from "sonner";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
const addEnviromentSchema = z.object({ const addEnvironmentSchema = z.object({
enviroment: z.string(), environment: z.string(),
}); });
type EnviromentSchema = z.infer<typeof addEnviromentSchema>; type EnvironmentSchema = z.infer<typeof addEnvironmentSchema>;
interface Props { interface Props {
redisId: string; redisId: string;
} }
export const ShowRedisEnviroment = ({ redisId }: Props) => { export const ShowRedisEnvironment = ({ redisId }: Props) => {
const { mutateAsync, isLoading } = api.redis.saveEnviroment.useMutation(); const { mutateAsync, isLoading } = api.redis.saveEnvironment.useMutation();
const { data, refetch } = api.redis.one.useQuery( const { data, refetch } = api.redis.one.useQuery(
{ {
@@ -42,32 +42,32 @@ export const ShowRedisEnviroment = ({ redisId }: Props) => {
enabled: !!redisId, enabled: !!redisId,
}, },
); );
const form = useForm<EnviromentSchema>({ const form = useForm<EnvironmentSchema>({
defaultValues: { defaultValues: {
enviroment: "", environment: "",
}, },
resolver: zodResolver(addEnviromentSchema), resolver: zodResolver(addEnvironmentSchema),
}); });
useEffect(() => { useEffect(() => {
if (data) { if (data) {
form.reset({ form.reset({
enviroment: data.env || "", environment: data.env || "",
}); });
} }
}, [form.reset, data, form]); }, [form.reset, data, form]);
const onSubmit = async (data: EnviromentSchema) => { const onSubmit = async (data: EnvironmentSchema) => {
mutateAsync({ mutateAsync({
env: data.enviroment, env: data.environment,
redisId, redisId,
}) })
.then(async () => { .then(async () => {
toast.success("Enviroments Added"); toast.success("Environments Added");
await refetch(); await refetch();
}) })
.catch(() => { .catch(() => {
toast.error("Error to add enviroment"); toast.error("Error to add environment");
}); });
}; };
@@ -75,9 +75,9 @@ export const ShowRedisEnviroment = ({ redisId }: Props) => {
<div className="flex w-full flex-col gap-5 "> <div className="flex w-full flex-col gap-5 ">
<Card className="bg-background"> <Card className="bg-background">
<CardHeader> <CardHeader>
<CardTitle className="text-xl">Enviroment Settings</CardTitle> <CardTitle className="text-xl">Environment Settings</CardTitle>
<CardDescription> <CardDescription>
You can add enviroment variables to your database. You can add environment variables to your database.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -89,7 +89,7 @@ export const ShowRedisEnviroment = ({ redisId }: Props) => {
> >
<FormField <FormField
control={form.control} control={form.control}
name="enviroment" name="environment"
render={({ field }) => ( render={({ field }) => (
<FormItem className="w-full"> <FormItem className="w-full">
<FormControl> <FormControl>

View File

@@ -31,6 +31,14 @@ export const generateName = () => {
n2[Math.round(Math.random() * (n2.length - 1))] n2[Math.round(Math.random() * (n2.length - 1))]
}`; }`;
}; };
function slugify(text: string) {
return text
.toLowerCase()
.replace(/[\s\^&*()+=!]+/g, "-")
.replace(/[\$.,*+~()'"!:@^&]+/g, "")
.replace(/-+/g, "-")
.replace(/^-+|-+$/g, "");
}
export const GithubSetup = () => { export const GithubSetup = () => {
const [isOrganization, setIsOrganization] = useState(false); const [isOrganization, setIsOrganization] = useState(false);
@@ -98,12 +106,17 @@ export const GithubSetup = () => {
your GitHub account. your GitHub account.
</span> </span>
<Link <div className="flex flex-row gap-4">
href={`https://github.com/apps/${data.githubAppName}/installations/new?state=gh_setup:${data?.authId}`} <Link
className={buttonVariants({ className: "w-fit" })} href={`https://github.com/apps/${slugify(
> data.githubAppName,
Install Github App )}/installations/new?state=gh_setup:${data?.authId}`}
</Link> className={buttonVariants({ className: "w-fit" })}
>
Install Github App
</Link>
<RemoveGithubApp />
</div>
</div> </div>
) : ( ) : (
<div> <div>

View File

@@ -39,6 +39,7 @@ export const RemoveGithubApp = () => {
await mutateAsync() await mutateAsync()
.then(async () => { .then(async () => {
await refetch(); await refetch();
utils.admin.one.invalidate();
await utils.admin.haveGithubConfigured.invalidate(); await utils.admin.haveGithubConfigured.invalidate();
toast.success("Github application deleted succesfully."); toast.success("Github application deleted succesfully.");
}) })

View File

@@ -1,7 +1,18 @@
#!/bin/bash #!/bin/bash
VERSION=$(node -p "require('./package.json').version") # Determine the type of build based on the first script argument
BUILD_TYPE=${1:-production}
docker build --platform linux/amd64 --pull --rm -f 'Dockerfile' -t "dokploy/dokploy:${VERSION}" . if [ "$BUILD_TYPE" == "canary" ]; then
TAG="canary"
else
VERSION=$(node -p "require('./package.json').version")
TAG="$VERSION"
fi
docker tag "dokploy/dokploy:${VERSION}" "dokploy/dokploy:latest" docker build --platform linux/amd64 --pull --rm -f 'Dockerfile' -t "dokploy/dokploy:${TAG}" .
if [ "$BUILD_TYPE" != "canary" ]; then
# Tag the production build as latest
docker tag "dokploy/dokploy:${TAG}" "dokploy/dokploy:latest"
fi

90
docker/canary.sh Normal file
View File

@@ -0,0 +1,90 @@
#!/bin/bash
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" >&2
exit 1
fi
# check if is Mac OS
if [ "$(uname)" = "Darwin" ]; then
echo "This script must be run on Linux" >&2
exit 1
fi
# check if is running inside a container
if [ -f /.dockerenv ]; then
echo "This script must be run on Linux" >&2
exit 1
fi
# check if something is running on port 80
if ss -tulnp | grep ':80 ' >/dev/null; then
echo "Error: something is already running on port 80" >&2
exit 1
fi
# check if something is running on port 443
if ss -tulnp | grep ':443 ' >/dev/null; then
echo "Error: something is already running on port 443" >&2
exit 1
fi
command_exists() {
command -v "$@" > /dev/null 2>&1
}
if command_exists docker; then
echo "Docker already installed"
else
curl -sSL https://get.docker.com | sh
fi
docker swarm leave --force 2>/dev/null
docker swarm init --advertise-addr 127.0.0.1 --listen-addr 0.0.0.0;
echo "Swarm initialized"
docker network rm -f dokploy-network 2>/dev/null
docker network create --driver overlay --attachable dokploy-network
echo "Network created"
mkdir -p /etc/dokploy
chmod -R 777 /etc/dokploy
docker pull dokploy/dokploy:canary
# Installation
docker service create \
--name dokploy \
--replicas 1 \
--network dokploy-network \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--mount type=bind,source=/etc/dokploy,target=/etc/dokploy \
--publish published=3000,target=3000,mode=host \
--update-parallelism 1 \
--update-order stop-first \
-e RELEASE_TAG=canary \
dokploy/dokploy:canary
public_ip=$(hostname -I | awk '{print $1}')
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
BLUE="\033[0;34m"
NC="\033[0m" # No Color
echo ""
printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n"
printf "${BLUE}Wait 15 seconds for the server to start${NC}\n"
printf "${YELLOW}Please go to http://${public_ip}:3000${NC}\n\n"
echo ""

View File

@@ -19,39 +19,21 @@ if [ -f /.dockerenv ]; then
fi fi
# check if something is running on port 80 # check if something is running on port 80
if lsof -i :80 >/dev/null; then if ss -tulnp | grep ':80 ' >/dev/null; then
echo "Error: something is already running on port 80" >&2 echo "Error: something is already running on port 80" >&2
exit 1 exit 1
fi fi
# check if something is running on port 443 # check if something is running on port 443
if lsof -i :443 >/dev/null; then if ss -tulnp | grep ':443 ' >/dev/null; then
echo "Error: something is already running on port 443" >&2 echo "Error: something is already running on port 443" >&2
exit 1 exit 1
fi fi
# Network
network_exists=$(docker network ls | grep dokploy-network)
if [ -z "$network_exists" ]; then
docker network create --driver overlay --attachable dokploy-network
echo "Network was initialized"
else
echo "Network is already initialized"
fi
# Swarm
swarm_status=$(docker info --format '{{.Swarm.LocalNodeState}}')
if [ "$swarm_status" = "active" ]; then
docker swarm leave --force 1> /dev/null 2> /dev/null || true
echo "Swarm is already initialized"
else
docker swarm init --advertise-addr 127.0.0.1 --listen-addr 0.0.0.0
echo "Swarm was initialized"
fi
command_exists() { command_exists() {
command -v "$@" > /dev/null 2>&1 command -v "$@" > /dev/null 2>&1
@@ -63,6 +45,20 @@ else
curl -sSL https://get.docker.com | sh curl -sSL https://get.docker.com | sh
fi fi
docker swarm leave --force 2>/dev/null
docker swarm init --advertise-addr 127.0.0.1 --listen-addr 0.0.0.0;
echo "Swarm initialized"
docker network rm -f dokploy-network 2>/dev/null
docker network create --driver overlay --attachable dokploy-network
echo "Network created"
mkdir -p /etc/dokploy
chmod -R 777 /etc/dokploy
docker pull dokploy/dokploy:latest docker pull dokploy/dokploy:latest
# Installation # Installation
@@ -75,4 +71,19 @@ docker service create \
--publish published=3000,target=3000,mode=host \ --publish published=3000,target=3000,mode=host \
--update-parallelism 1 \ --update-parallelism 1 \
--update-order stop-first \ --update-order stop-first \
dokploy/dokploy:latest dokploy/dokploy:latest
public_ip=$(hostname -I | awk '{print $1}')
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
BLUE="\033[0;34m"
NC="\033[0m" # No Color
echo ""
printf "${GREEN}Congratulations, Dokploy is installed!${NC}\n"
printf "${BLUE}Wait 15 seconds for the server to start${NC}\n"
printf "${YELLOW}Please go to http://${public_ip}:3000${NC}\n\n"
echo ""

View File

@@ -1,6 +1,15 @@
#!/bin/bash #!/bin/bash
VERSION=$(node -p "require('./package.json').version") # Determine the type of build based on the first script argument
BUILD_TYPE=${1:-production}
docker push "dokploy/dokploy:${VERSION}" if [ "$BUILD_TYPE" == "canary" ]; then
docker push "dokploy/dokploy:latest" TAG="canary"
echo PUSHING CANARY
docker push "dokploy/dokploy:${TAG}"
else
echo "PUSHING PRODUCTION"
VERSION=$(node -p "require('./package.json').version")
docker push "dokploy/dokploy:${VERSION}"
docker push "dokploy/dokploy:latest"
fi

20
migration.ts Normal file
View File

@@ -0,0 +1,20 @@
import { drizzle } from "drizzle-orm/postgres-js";
import { migrate } from "drizzle-orm/postgres-js/migrator";
import postgres from "postgres";
const connectionString = process.env.DATABASE_URL || "";
const sql = postgres(connectionString, { max: 1 });
const db = drizzle(sql);
await migrate(db, { migrationsFolder: "drizzle" })
.then(() => {
console.log("Migration complete");
sql.end();
})
.catch((error) => {
console.log("Migration failed", error);
})
.finally(() => {
sql.end();
});

View File

@@ -9,18 +9,22 @@
"start": "node dist/server.mjs", "start": "node dist/server.mjs",
"build-server": "tsx esbuild.config.ts", "build-server": "tsx esbuild.config.ts",
"build-next": "next build", "build-next": "next build",
"setup": "tsx -r dotenv/config setup.ts && sleep 5 && pnpm run migration:run",
"reset-password": "node dist/reset-password.mjs", "reset-password": "node dist/reset-password.mjs",
"dev": "tsx watch -r dotenv/config ./server/server.ts --project tsconfig.server.json ", "dev": "tsx watch -r dotenv/config ./server/server.ts --project tsconfig.server.json ",
"migration:generate": "drizzle-kit generate:pg --config ./server/db/drizzle.config.ts", "migration:generate": "drizzle-kit generate:pg --config ./server/db/drizzle.config.ts",
"migration:run": "tsx -r dotenv/config migration.ts", "migration:run": "tsx -r dotenv/config migration.ts",
"migration:drop": "drizzle-kit drop --config ./server/db/drizzle.config.ts", "migration:drop": "drizzle-kit drop --config ./server/db/drizzle.config.ts",
"db:push": "drizzle-kit push:pg --config ./server/db/drizzle.config.ts", "db:push": "drizzle-kit push:pg --config ./server/db/drizzle.config.ts",
"db:truncate": "tsx -r dotenv/config ./server/db/reset.ts",
"db:studio": "drizzle-kit studio", "db:studio": "drizzle-kit studio",
"lint": "biome lint", "lint": "biome lint",
"db:seed": "dotenv tsx ./server/db/seed.ts", "db:seed": "dotenv tsx ./server/db/seed.ts",
"db:clean": "dotenv tsx ./server/db/reset.ts", "db:clean": "dotenv tsx ./server/db/reset.ts",
"docker:build": "./docker/build.sh", "docker:build": "./docker/build.sh",
"docker:push": "./docker/push.sh", "docker:push": "./docker/push.sh",
"docker:build:canary": "./docker/build.sh canary",
"docker:push:canary": "./docker/push.sh canary",
"version": "echo $(node -p \"require('./package.json').version\")" "version": "echo $(node -p \"require('./package.json').version\")"
}, },
"dependencies": { "dependencies": {
@@ -127,6 +131,7 @@
"initVersion": "7.25.2" "initVersion": "7.25.2"
}, },
"engines": { "engines": {
"node": "18.x" "node": "^18.18.0",
"pnpm": ">=8.15.4"
} }
} }

View File

@@ -8,7 +8,7 @@ import { ShowVolumes } from "@/components/dashboard/application/advanced/volumes
import { DeleteApplication } from "@/components/dashboard/application/delete-application"; import { DeleteApplication } from "@/components/dashboard/application/delete-application";
import { ShowDeployments } from "@/components/dashboard/application/deployments/show-deployments"; import { ShowDeployments } from "@/components/dashboard/application/deployments/show-deployments";
import { ShowDomains } from "@/components/dashboard/application/domains/show-domains"; import { ShowDomains } from "@/components/dashboard/application/domains/show-domains";
import { ShowEnviroment } from "@/components/dashboard/application/enviroment/show"; import { ShowEnvironment } from "@/components/dashboard/application/environment/show";
import { ShowGeneralApplication } from "@/components/dashboard/application/general/show"; import { ShowGeneralApplication } from "@/components/dashboard/application/general/show";
import { ShowDockerLogs } from "@/components/dashboard/application/logs/show"; import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { UpdateApplication } from "@/components/dashboard/application/update-application"; import { UpdateApplication } from "@/components/dashboard/application/update-application";
@@ -127,7 +127,7 @@ const Service = (
<div className="flex flex-row items-center justify-between w-full gap-4"> <div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-7 max-md:overflow-y-scroll justify-start"> <TabsList className="md:grid md:w-fit md:grid-cols-7 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger> <TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger> <TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger> <TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger> <TabsTrigger value="logs">Logs</TabsTrigger>
<TabsTrigger value="deployments">Deployments</TabsTrigger> <TabsTrigger value="deployments">Deployments</TabsTrigger>
@@ -147,9 +147,9 @@ const Service = (
<ShowGeneralApplication applicationId={applicationId} /> <ShowGeneralApplication applicationId={applicationId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="enviroment"> <TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5"> <div className="flex flex-col gap-4 pt-2.5">
<ShowEnviroment applicationId={applicationId} /> <ShowEnvironment applicationId={applicationId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="monitoring"> <TabsContent value="monitoring">
@@ -242,7 +242,7 @@ export async function getServerSideProps(
return { return {
redirect: { redirect: {
permanent: false, permanent: false,
destination: "/dashboard", destination: "/dashboard/projects",
}, },
}; };
} }

View File

@@ -2,7 +2,7 @@ import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { ShowAdvancedMariadb } from "@/components/dashboard/mariadb/advanced/show-mariadb-advanced-settings"; import { ShowAdvancedMariadb } from "@/components/dashboard/mariadb/advanced/show-mariadb-advanced-settings";
import { ShowBackupMariadb } from "@/components/dashboard/mariadb/backups/show-backup-mariadb"; import { ShowBackupMariadb } from "@/components/dashboard/mariadb/backups/show-backup-mariadb";
import { DeleteMariadb } from "@/components/dashboard/mariadb/delete-mariadb"; import { DeleteMariadb } from "@/components/dashboard/mariadb/delete-mariadb";
import { ShowMariadbEnviroment } from "@/components/dashboard/mariadb/enviroment/show-mariadb-enviroment"; import { ShowMariadbEnvironment } from "@/components/dashboard/mariadb/environment/show-mariadb-environment";
import { ShowExternalMariadbCredentials } from "@/components/dashboard/mariadb/general/show-external-mariadb-credentials"; import { ShowExternalMariadbCredentials } from "@/components/dashboard/mariadb/general/show-external-mariadb-credentials";
import { ShowGeneralMariadb } from "@/components/dashboard/mariadb/general/show-general-mariadb"; import { ShowGeneralMariadb } from "@/components/dashboard/mariadb/general/show-general-mariadb";
import { ShowInternalMariadbCredentials } from "@/components/dashboard/mariadb/general/show-internal-mariadb-credentials"; import { ShowInternalMariadbCredentials } from "@/components/dashboard/mariadb/general/show-internal-mariadb-credentials";
@@ -110,7 +110,7 @@ const Mariadb = (
<div className="flex flex-row items-center justify-between w-full gap-4"> <div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start"> <TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger> <TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger> <TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger> <TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="backups">Backups</TabsTrigger> <TabsTrigger value="backups">Backups</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger> <TabsTrigger value="logs">Logs</TabsTrigger>
@@ -131,9 +131,9 @@ const Mariadb = (
<ShowExternalMariadbCredentials mariadbId={mariadbId} /> <ShowExternalMariadbCredentials mariadbId={mariadbId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="enviroment"> <TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5"> <div className="flex flex-col gap-4 pt-2.5">
<ShowMariadbEnviroment mariadbId={mariadbId} /> <ShowMariadbEnvironment mariadbId={mariadbId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="monitoring"> <TabsContent value="monitoring">
@@ -211,7 +211,7 @@ export async function getServerSideProps(
return { return {
redirect: { redirect: {
permanent: false, permanent: false,
destination: "/dashboard", destination: "/dashboard/projects",
}, },
}; };
} }

View File

@@ -2,7 +2,7 @@ import { ShowDockerLogs } from "@/components/dashboard/application/logs/show";
import { ShowAdvancedMongo } from "@/components/dashboard/mongo/advanced/show-mongo-advanced-settings"; import { ShowAdvancedMongo } from "@/components/dashboard/mongo/advanced/show-mongo-advanced-settings";
import { ShowBackupMongo } from "@/components/dashboard/mongo/backups/show-backup-mongo"; import { ShowBackupMongo } from "@/components/dashboard/mongo/backups/show-backup-mongo";
import { DeleteMongo } from "@/components/dashboard/mongo/delete-mongo"; import { DeleteMongo } from "@/components/dashboard/mongo/delete-mongo";
import { ShowMongoEnviroment } from "@/components/dashboard/mongo/enviroment/show-mongo-enviroment"; import { ShowMongoEnvironment } from "@/components/dashboard/mongo/environment/show-mongo-environment";
import { ShowExternalMongoCredentials } from "@/components/dashboard/mongo/general/show-external-mongo-credentials"; import { ShowExternalMongoCredentials } from "@/components/dashboard/mongo/general/show-external-mongo-credentials";
import { ShowGeneralMongo } from "@/components/dashboard/mongo/general/show-general-mongo"; import { ShowGeneralMongo } from "@/components/dashboard/mongo/general/show-general-mongo";
import { ShowInternalMongoCredentials } from "@/components/dashboard/mongo/general/show-internal-mongo-credentials"; import { ShowInternalMongoCredentials } from "@/components/dashboard/mongo/general/show-internal-mongo-credentials";
@@ -111,7 +111,7 @@ const Mongo = (
<div className="flex flex-row items-center justify-between w-full gap-4"> <div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start"> <TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger> <TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger> <TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger> <TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="backups">Backups</TabsTrigger> <TabsTrigger value="backups">Backups</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger> <TabsTrigger value="logs">Logs</TabsTrigger>
@@ -133,9 +133,9 @@ const Mongo = (
<ShowExternalMongoCredentials mongoId={mongoId} /> <ShowExternalMongoCredentials mongoId={mongoId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="enviroment"> <TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5"> <div className="flex flex-col gap-4 pt-2.5">
<ShowMongoEnviroment mongoId={mongoId} /> <ShowMongoEnvironment mongoId={mongoId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="monitoring"> <TabsContent value="monitoring">
@@ -213,7 +213,7 @@ export async function getServerSideProps(
return { return {
redirect: { redirect: {
permanent: false, permanent: false,
destination: "/dashboard", destination: "/dashboard/projects",
}, },
}; };
} }

View File

@@ -1,7 +1,7 @@
import { ShowAdvancedMysql } from "@/components/dashboard/mysql/advanced/show-mysql-advanced-settings"; import { ShowAdvancedMysql } from "@/components/dashboard/mysql/advanced/show-mysql-advanced-settings";
import { ShowBackupMySql } from "@/components/dashboard/mysql/backups/show-backup-mysql"; import { ShowBackupMySql } from "@/components/dashboard/mysql/backups/show-backup-mysql";
import { DeleteMysql } from "@/components/dashboard/mysql/delete-mysql"; import { DeleteMysql } from "@/components/dashboard/mysql/delete-mysql";
import { ShowMysqlEnviroment } from "@/components/dashboard/mysql/enviroment/show-mysql-enviroment"; import { ShowMysqlEnvironment } from "@/components/dashboard/mysql/environment/show-mysql-environment";
import { ShowExternalMysqlCredentials } from "@/components/dashboard/mysql/general/show-external-mysql-credentials"; import { ShowExternalMysqlCredentials } from "@/components/dashboard/mysql/general/show-external-mysql-credentials";
import { ShowGeneralMysql } from "@/components/dashboard/mysql/general/show-general-mysql"; import { ShowGeneralMysql } from "@/components/dashboard/mysql/general/show-general-mysql";
import { ShowInternalMysqlCredentials } from "@/components/dashboard/mysql/general/show-internal-mysql-credentials"; import { ShowInternalMysqlCredentials } from "@/components/dashboard/mysql/general/show-internal-mysql-credentials";
@@ -110,7 +110,7 @@ const MySql = (
<div className="flex flex-row items-center justify-between w-full gap-4"> <div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start"> <TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger> <TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger> <TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger> <TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="backups">Backups</TabsTrigger> <TabsTrigger value="backups">Backups</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger> <TabsTrigger value="logs">Logs</TabsTrigger>
@@ -132,9 +132,9 @@ const MySql = (
<ShowExternalMysqlCredentials mysqlId={mysqlId} /> <ShowExternalMysqlCredentials mysqlId={mysqlId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="enviroment" className="w-full"> <TabsContent value="environment" className="w-full">
<div className="flex flex-col gap-4 pt-2.5"> <div className="flex flex-col gap-4 pt-2.5">
<ShowMysqlEnviroment mysqlId={mysqlId} /> <ShowMysqlEnvironment mysqlId={mysqlId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="monitoring"> <TabsContent value="monitoring">
@@ -212,7 +212,7 @@ export async function getServerSideProps(
return { return {
redirect: { redirect: {
permanent: false, permanent: false,
destination: "/dashboard", destination: "/dashboard/projects",
}, },
}; };
} }

View File

@@ -1,7 +1,7 @@
import { ShowAdvancedPostgres } from "@/components/dashboard/postgres/advanced/show-postgres-advanced-settings"; import { ShowAdvancedPostgres } from "@/components/dashboard/postgres/advanced/show-postgres-advanced-settings";
import { ShowBackupPostgres } from "@/components/dashboard/postgres/backups/show-backup-postgres"; import { ShowBackupPostgres } from "@/components/dashboard/postgres/backups/show-backup-postgres";
import { DeletePostgres } from "@/components/dashboard/postgres/delete-postgres"; import { DeletePostgres } from "@/components/dashboard/postgres/delete-postgres";
import { ShowPostgresEnviroment } from "@/components/dashboard/postgres/enviroment/show-postgres-enviroment"; import { ShowPostgresEnvironment } from "@/components/dashboard/postgres/environment/show-postgres-environment";
import { ShowExternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-external-postgres-credentials"; import { ShowExternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-external-postgres-credentials";
import { ShowGeneralPostgres } from "@/components/dashboard/postgres/general/show-general-postgres"; import { ShowGeneralPostgres } from "@/components/dashboard/postgres/general/show-general-postgres";
import { ShowInternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-internal-postgres-credentials"; import { ShowInternalPostgresCredentials } from "@/components/dashboard/postgres/general/show-internal-postgres-credentials";
@@ -111,7 +111,7 @@ const Postgresql = (
<div className="flex flex-row items-center justify-between w-full gap-4"> <div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start"> <TabsList className="md:grid md:w-fit md:grid-cols-6 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger> <TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger> <TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger> <TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="backups">Backups</TabsTrigger> <TabsTrigger value="backups">Backups</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger> <TabsTrigger value="logs">Logs</TabsTrigger>
@@ -133,9 +133,9 @@ const Postgresql = (
<ShowExternalPostgresCredentials postgresId={postgresId} /> <ShowExternalPostgresCredentials postgresId={postgresId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="enviroment"> <TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5"> <div className="flex flex-col gap-4 pt-2.5">
<ShowPostgresEnviroment postgresId={postgresId} /> <ShowPostgresEnvironment postgresId={postgresId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="monitoring"> <TabsContent value="monitoring">
@@ -212,7 +212,7 @@ export async function getServerSideProps(
return { return {
redirect: { redirect: {
permanent: false, permanent: false,
destination: "/dashboard", destination: "/dashboard/projects",
}, },
}; };
} }

View File

@@ -1,6 +1,6 @@
import { ShowAdvancedRedis } from "@/components/dashboard/redis/advanced/show-redis-advanced-settings"; import { ShowAdvancedRedis } from "@/components/dashboard/redis/advanced/show-redis-advanced-settings";
import { DeleteRedis } from "@/components/dashboard/redis/delete-redis"; import { DeleteRedis } from "@/components/dashboard/redis/delete-redis";
import { ShowRedisEnviroment } from "@/components/dashboard/redis/enviroment/show-redis-enviroment"; import { ShowRedisEnvironment } from "@/components/dashboard/redis/environment/show-redis-environment";
import { ShowExternalRedisCredentials } from "@/components/dashboard/redis/general/show-external-redis-credentials"; import { ShowExternalRedisCredentials } from "@/components/dashboard/redis/general/show-external-redis-credentials";
import { ShowGeneralRedis } from "@/components/dashboard/redis/general/show-general-redis"; import { ShowGeneralRedis } from "@/components/dashboard/redis/general/show-general-redis";
import { ShowInternalRedisCredentials } from "@/components/dashboard/redis/general/show-internal-redis-credentials"; import { ShowInternalRedisCredentials } from "@/components/dashboard/redis/general/show-internal-redis-credentials";
@@ -110,7 +110,7 @@ const Redis = (
<div className="flex flex-row items-center justify-between w-full gap-4"> <div className="flex flex-row items-center justify-between w-full gap-4">
<TabsList className="md:grid md:w-fit md:grid-cols-5 max-md:overflow-y-scroll justify-start"> <TabsList className="md:grid md:w-fit md:grid-cols-5 max-md:overflow-y-scroll justify-start">
<TabsTrigger value="general">General</TabsTrigger> <TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="enviroment">Enviroment</TabsTrigger> <TabsTrigger value="environment">Environment</TabsTrigger>
<TabsTrigger value="monitoring">Monitoring</TabsTrigger> <TabsTrigger value="monitoring">Monitoring</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger> <TabsTrigger value="logs">Logs</TabsTrigger>
<TabsTrigger value="advanced">Advanced</TabsTrigger> <TabsTrigger value="advanced">Advanced</TabsTrigger>
@@ -131,9 +131,9 @@ const Redis = (
<ShowExternalRedisCredentials redisId={redisId} /> <ShowExternalRedisCredentials redisId={redisId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="enviroment"> <TabsContent value="environment">
<div className="flex flex-col gap-4 pt-2.5"> <div className="flex flex-col gap-4 pt-2.5">
<ShowRedisEnviroment redisId={redisId} /> <ShowRedisEnvironment redisId={redisId} />
</div> </div>
</TabsContent> </TabsContent>
<TabsContent value="monitoring"> <TabsContent value="monitoring">
@@ -205,7 +205,7 @@ export async function getServerSideProps(
return { return {
redirect: { redirect: {
permanent: false, permanent: false,
destination: "/dashboard", destination: "/dashboard/projects",
}, },
}; };
} }

View File

@@ -38,7 +38,6 @@ export async function getServerSideProps(
}, },
}; };
} }
console.log(user);
if (user.rol === "user") { if (user.rol === "user") {
return { return {
redirect: { redirect: {

View File

@@ -7,7 +7,7 @@ import {
apiReloadApplication, apiReloadApplication,
apiSaveBuildType, apiSaveBuildType,
apiSaveDockerProvider, apiSaveDockerProvider,
apiSaveEnviromentVariables, apiSaveEnvironmentVariables,
apiSaveGitProvider, apiSaveGitProvider,
apiSaveGithubProvider, apiSaveGithubProvider,
apiUpdateApplication, apiUpdateApplication,
@@ -170,8 +170,8 @@ export const applicationRouter = createTRPCRouter({
}, },
); );
}), }),
saveEnviroment: protectedProcedure saveEnvironment: protectedProcedure
.input(apiSaveEnviromentVariables) .input(apiSaveEnvironmentVariables)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
await updateApplication(input.applicationId, { await updateApplication(input.applicationId, {
env: input.env, env: input.env,

View File

@@ -5,7 +5,7 @@ import {
apiDeployMariaDB, apiDeployMariaDB,
apiFindOneMariaDB, apiFindOneMariaDB,
apiResetMariadb, apiResetMariadb,
apiSaveEnviromentVariablesMariaDB, apiSaveEnvironmentVariablesMariaDB,
apiSaveExternalPortMariaDB, apiSaveExternalPortMariaDB,
apiUpdateMariaDB, apiUpdateMariaDB,
} from "@/server/db/schema/mariadb"; } from "@/server/db/schema/mariadb";
@@ -134,8 +134,8 @@ export const mariadbRouter = createTRPCRouter({
return mongo; return mongo;
}), }),
saveEnviroment: protectedProcedure saveEnvironment: protectedProcedure
.input(apiSaveEnviromentVariablesMariaDB) .input(apiSaveEnvironmentVariablesMariaDB)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
const service = await updateMariadbById(input.mariadbId, { const service = await updateMariadbById(input.mariadbId, {
env: input.env, env: input.env,
@@ -144,7 +144,7 @@ export const mariadbRouter = createTRPCRouter({
if (!service) { if (!service) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables", message: "Update: Error to add environment variables",
}); });
} }

View File

@@ -5,7 +5,7 @@ import {
apiDeployMongo, apiDeployMongo,
apiFindOneMongo, apiFindOneMongo,
apiResetMongo, apiResetMongo,
apiSaveEnviromentVariablesMongo, apiSaveEnvironmentVariablesMongo,
apiSaveExternalPortMongo, apiSaveExternalPortMongo,
apiUpdateMongo, apiUpdateMongo,
} from "@/server/db/schema/mongo"; } from "@/server/db/schema/mongo";
@@ -148,8 +148,8 @@ export const mongoRouter = createTRPCRouter({
return mongo; return mongo;
}), }),
saveEnviroment: protectedProcedure saveEnvironment: protectedProcedure
.input(apiSaveEnviromentVariablesMongo) .input(apiSaveEnvironmentVariablesMongo)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
const service = await updateMongoById(input.mongoId, { const service = await updateMongoById(input.mongoId, {
env: input.env, env: input.env,
@@ -158,7 +158,7 @@ export const mongoRouter = createTRPCRouter({
if (!service) { if (!service) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables", message: "Update: Error to add environment variables",
}); });
} }

View File

@@ -5,7 +5,7 @@ import {
apiDeployMySql, apiDeployMySql,
apiFindOneMySql, apiFindOneMySql,
apiResetMysql, apiResetMysql,
apiSaveEnviromentVariablesMySql, apiSaveEnvironmentVariablesMySql,
apiSaveExternalPortMySql, apiSaveExternalPortMySql,
apiUpdateMySql, apiUpdateMySql,
} from "@/server/db/schema/mysql"; } from "@/server/db/schema/mysql";
@@ -147,8 +147,8 @@ export const mysqlRouter = createTRPCRouter({
return mongo; return mongo;
}), }),
saveEnviroment: protectedProcedure saveEnvironment: protectedProcedure
.input(apiSaveEnviromentVariablesMySql) .input(apiSaveEnvironmentVariablesMySql)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
const service = await updateMySqlById(input.mysqlId, { const service = await updateMySqlById(input.mysqlId, {
env: input.env, env: input.env,
@@ -157,7 +157,7 @@ export const mysqlRouter = createTRPCRouter({
if (!service) { if (!service) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables", message: "Update: Error to add environment variables",
}); });
} }

View File

@@ -5,7 +5,7 @@ import {
apiDeployPostgres, apiDeployPostgres,
apiFindOnePostgres, apiFindOnePostgres,
apiResetPostgres, apiResetPostgres,
apiSaveEnviromentVariablesPostgres, apiSaveEnvironmentVariablesPostgres,
apiSaveExternalPortPostgres, apiSaveExternalPortPostgres,
apiUpdatePostgres, apiUpdatePostgres,
} from "@/server/db/schema/postgres"; } from "@/server/db/schema/postgres";
@@ -130,8 +130,8 @@ export const postgresRouter = createTRPCRouter({
return postgres; return postgres;
}), }),
saveEnviroment: protectedProcedure saveEnvironment: protectedProcedure
.input(apiSaveEnviromentVariablesPostgres) .input(apiSaveEnvironmentVariablesPostgres)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
const service = await updatePostgresById(input.postgresId, { const service = await updatePostgresById(input.postgresId, {
env: input.env, env: input.env,
@@ -140,7 +140,7 @@ export const postgresRouter = createTRPCRouter({
if (!service) { if (!service) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables", message: "Update: Error to add environment variables",
}); });
} }

View File

@@ -42,6 +42,8 @@ export const projectRouter = createTRPCRouter({
if (ctx.user.rol === "user") { if (ctx.user.rol === "user") {
await addNewProject(ctx.user.authId, project.projectId); await addNewProject(ctx.user.authId, project.projectId);
} }
return project;
} catch (error) { } catch (error) {
console.log(error); console.log(error);
throw new TRPCError({ throw new TRPCError({

View File

@@ -5,7 +5,7 @@ import {
apiDeployRedis, apiDeployRedis,
apiFindOneRedis, apiFindOneRedis,
apiResetRedis, apiResetRedis,
apiSaveEnviromentVariablesRedis, apiSaveEnvironmentVariablesRedis,
apiSaveExternalPortRedis, apiSaveExternalPortRedis,
apiUpdateRedis, apiUpdateRedis,
} from "@/server/db/schema/redis"; } from "@/server/db/schema/redis";
@@ -147,8 +147,8 @@ export const redisRouter = createTRPCRouter({
return redis; return redis;
}), }),
saveEnviroment: protectedProcedure saveEnvironment: protectedProcedure
.input(apiSaveEnviromentVariablesRedis) .input(apiSaveEnvironmentVariablesRedis)
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
const redis = await updateRedisById(input.redisId, { const redis = await updateRedisById(input.redisId, {
env: input.env, env: input.env,
@@ -157,7 +157,7 @@ export const redisRouter = createTRPCRouter({
if (!redis) { if (!redis) {
throw new TRPCError({ throw new TRPCError({
code: "BAD_REQUEST", code: "BAD_REQUEST",
message: "Update: Error to add enviroment variables", message: "Update: Error to add environment variables",
}); });
} }

View File

@@ -16,7 +16,7 @@ const updateIsAvailable = async () => {
}; };
export const getDokployImage = () => { export const getDokployImage = () => {
return "dokploy/dokploy:latest"; return `dokploy/dokploy:${process.env.RELEASE_TAG || "latest"}`;
}; };
export const pullLatestRelease = async () => { export const pullLatestRelease = async () => {

View File

@@ -1,6 +1,10 @@
import Docker from "dockerode"; import Docker from "dockerode";
import path from "node:path";
export const BASE_PATH = "/etc/dokploy"; export const BASE_PATH =
process.env.NODE_ENV === "production"
? "/etc/dokploy"
: path.join(process.cwd(), ".docker");
export const MAIN_TRAEFIK_PATH = `${BASE_PATH}/traefik`; export const MAIN_TRAEFIK_PATH = `${BASE_PATH}/traefik`;
export const DYNAMIC_TRAEFIK_PATH = `${BASE_PATH}/traefik/dynamic`; export const DYNAMIC_TRAEFIK_PATH = `${BASE_PATH}/traefik/dynamic`;
export const LOGS_PATH = `${BASE_PATH}/logs`; export const LOGS_PATH = `${BASE_PATH}/logs`;

View File

@@ -10,9 +10,10 @@ const db = drizzle(pg);
const clearDb = async (): Promise<void> => { const clearDb = async (): Promise<void> => {
try { try {
const tablesQuery = sql<string>`DROP SCHEMA public CASCADE; CREATE SCHEMA public;`; const tablesQuery = sql<string>`DROP SCHEMA public CASCADE; CREATE SCHEMA public; DROP schema drizzle CASCADE;`;
const tables = await db.execute(tablesQuery); const tables = await db.execute(tablesQuery);
console.log(tables); console.log(tables);
await pg.end();
} catch (error) { } catch (error) {
console.error("Error to clean database", error); console.error("Error to clean database", error);
} finally { } finally {

View File

@@ -181,7 +181,7 @@ export const apiSaveGitProvider = createSchema
}) })
.required(); .required();
export const apiSaveEnviromentVariables = createSchema export const apiSaveEnvironmentVariables = createSchema
.pick({ .pick({
applicationId: true, applicationId: true,
env: true, env: true,

View File

@@ -102,7 +102,7 @@ export const apiChangeMariaDBStatus = createSchema
}) })
.required(); .required();
export const apiSaveEnviromentVariablesMariaDB = createSchema export const apiSaveEnvironmentVariablesMariaDB = createSchema
.pick({ .pick({
mariadbId: true, mariadbId: true,
env: true, env: true,

View File

@@ -94,7 +94,7 @@ export const apiChangeMongoStatus = createSchema
}) })
.required(); .required();
export const apiSaveEnviromentVariablesMongo = createSchema export const apiSaveEnvironmentVariablesMongo = createSchema
.pick({ .pick({
mongoId: true, mongoId: true,
env: true, env: true,

View File

@@ -100,7 +100,7 @@ export const apiChangeMySqlStatus = createSchema
}) })
.required(); .required();
export const apiSaveEnviromentVariablesMySql = createSchema export const apiSaveEnvironmentVariablesMySql = createSchema
.pick({ .pick({
mysqlId: true, mysqlId: true,
env: true, env: true,

View File

@@ -96,7 +96,7 @@ export const apiChangePostgresStatus = createSchema
}) })
.required(); .required();
export const apiSaveEnviromentVariablesPostgres = createSchema export const apiSaveEnvironmentVariablesPostgres = createSchema
.pick({ .pick({
postgresId: true, postgresId: true,
env: true, env: true,

View File

@@ -90,7 +90,7 @@ export const apiChangeRedisStatus = createSchema
}) })
.required(); .required();
export const apiSaveEnviromentVariablesRedis = createSchema export const apiSaveEnvironmentVariablesRedis = createSchema
.pick({ .pick({
redisId: true, redisId: true,
env: true, env: true,

View File

@@ -34,31 +34,32 @@ void app.prepare().then(async () => {
handle(req, res); handle(req, res);
}); });
setupDirectories();
createDefaultMiddlewares();
await initializeNetwork();
await initializeSwarm();
createDefaultTraefikConfig();
createDefaultServerTraefikConfig();
await initializeTraefik();
await initializeRedis();
await initializePostgres();
// WEBSOCKET // WEBSOCKET
setupDeploymentLogsWebSocketServer(server); setupDeploymentLogsWebSocketServer(server);
setupDockerContainerLogsWebSocketServer(server); setupDockerContainerLogsWebSocketServer(server);
setupDockerContainerTerminalWebSocketServer(server); setupDockerContainerTerminalWebSocketServer(server);
setupTerminalWebSocketServer(server); setupTerminalWebSocketServer(server);
setupDockerStatsMonitoringSocketServer(server); setupDockerStatsMonitoringSocketServer(server);
if (process.env.NODE_ENV === "production") { if (process.env.NODE_ENV === "production") {
// Cron Jobs setupDirectories();
createDefaultMiddlewares();
await initializeSwarm();
await initializeNetwork();
createDefaultTraefikConfig();
createDefaultServerTraefikConfig();
await initializeTraefik();
await initializeRedis();
await initializePostgres();
initCronJobs(); initCronJobs();
welcomeServer(); welcomeServer();
// Timeout to wait for the database to be ready
await new Promise((resolve) => setTimeout(resolve, 7000)); await new Promise((resolve) => setTimeout(resolve, 7000));
await migration(); await migration();
} }
server.listen(PORT); server.listen(PORT);
console.log("Server Started:", PORT);
deploymentWorker.run(); deploymentWorker.run();
} catch (e) { } catch (e) {
console.error("Main Server Error", e); console.error("Main Server Error", e);

View File

@@ -56,7 +56,6 @@ export const initializePostgres = async () => {
console.log("Postgres Started ✅"); console.log("Postgres Started ✅");
} catch (error) { } catch (error) {
console.log(error);
await docker.createService(settings); await docker.createService(settings);
console.log("Postgres Not Found: Starting ✅"); console.log("Postgres Not Found: Starting ✅");
} }

View File

@@ -19,7 +19,6 @@ export const dockerSwarmInitialized = async () => {
return true; return true;
} catch (e) { } catch (e) {
console.log(e);
return false; return false;
} }
}; };

View File

@@ -133,7 +133,7 @@ export const createDefaultTraefikConfig = () => {
}, },
}), }),
file: { file: {
directory: DYNAMIC_TRAEFIK_PATH, directory: "/etc/dokploy/traefik/dynamic",
watch: true, watch: true,
}, },
}, },

View File

@@ -6,35 +6,35 @@ import type { WriteStream } from "node:fs";
// TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker // TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker
export const buildHeroku = async ( export const buildHeroku = async (
application: ApplicationNested, application: ApplicationNested,
writeStream: WriteStream, writeStream: WriteStream,
) => { ) => {
const { env, appName } = application; const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application); const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env); const envVariables = prepareEnvironmentVariables(env);
try { try {
const args = [ const args = [
"build", "build",
appName, appName,
"--path", "--path",
buildAppDirectory, buildAppDirectory,
"--builder", "--builder",
"heroku/builder:22", "heroku/builder:22",
]; ];
for (const env in envVariables) { for (const env of envVariables) {
args.push("--env", env); args.push("--env", env);
} }
await spawnAsync("pack", args, (data) => { await spawnAsync("pack", args, (data) => {
if (writeStream.writable) { if (writeStream.writable) {
writeStream.write(data); writeStream.write(data);
} }
// Stream the data // Stream the data
console.log(data); console.log(data);
}); });
return true; return true;
} catch (e) { } catch (e) {
throw e; throw e;
} }
}; };

View File

@@ -6,25 +6,26 @@ import type { WriteStream } from "node:fs";
// TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker // TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker
export const buildNixpacks = async ( export const buildNixpacks = async (
application: ApplicationNested, application: ApplicationNested,
writeStream: WriteStream, writeStream: WriteStream,
) => { ) => {
const { env, appName } = application; const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application); const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env); const envVariables = prepareEnvironmentVariables(env);
try { try {
const args = ["build", buildAppDirectory, "--name", appName]; const args = ["build", buildAppDirectory, "--name", appName];
for (const env in envVariables) { for (const env of envVariables) {
args.push("--env", env); args.push("--env", env);
} }
await spawnAsync("nixpacks", args, (data) => {
if (writeStream.writable) { await spawnAsync("nixpacks", args, (data) => {
writeStream.write(data); if (writeStream.writable) {
} writeStream.write(data);
}); }
return true; });
} catch (e) { return true;
throw e; } catch (e) {
} throw e;
}
}; };

View File

@@ -6,33 +6,33 @@ import { prepareEnvironmentVariables } from "../docker/utils";
// TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker // TODO: integrate in the vps sudo chown -R $(whoami) ~/.docker
export const buildPaketo = async ( export const buildPaketo = async (
application: ApplicationNested, application: ApplicationNested,
writeStream: WriteStream, writeStream: WriteStream,
) => { ) => {
const { env, appName } = application; const { env, appName } = application;
const buildAppDirectory = getBuildAppDirectory(application); const buildAppDirectory = getBuildAppDirectory(application);
const envVariables = prepareEnvironmentVariables(env); const envVariables = prepareEnvironmentVariables(env);
try { try {
const args = [ const args = [
"build", "build",
appName, appName,
"--path", "--path",
buildAppDirectory, buildAppDirectory,
"--builder", "--builder",
"paketobuildpacks/builder-jammy-full", "paketobuildpacks/builder-jammy-full",
]; ];
for (const env in envVariables) { for (const env of envVariables) {
args.push("--env", env); args.push("--env", env);
} }
await spawnAsync("pack", args, (data) => { await spawnAsync("pack", args, (data) => {
if (writeStream.writable) { if (writeStream.writable) {
writeStream.write(data); writeStream.write(data);
} }
}); });
return true; return true;
} catch (e) { } catch (e) {
throw e; throw e;
} }
}; };

26
setup.ts Normal file
View File

@@ -0,0 +1,26 @@
import {
createDefaultMiddlewares,
createDefaultServerTraefikConfig,
createDefaultTraefikConfig,
initializeTraefik,
} from "./server/setup/traefik-setup";
import { initializeRedis } from "./server/setup/redis-setup";
import { initializePostgres } from "./server/setup/postgres-setup";
import { setupDirectories } from "./server/setup/config-paths";
import { initializeNetwork, initializeSwarm } from "./server/setup/setup";
(async () => {
try {
setupDirectories();
createDefaultMiddlewares();
await initializeSwarm();
await initializeNetwork();
createDefaultTraefikConfig();
createDefaultServerTraefikConfig();
await initializeTraefik();
await initializeRedis();
await initializePostgres();
} catch (e) {
console.error("Error to setup dokploy", e);
}
})();

View File

@@ -39,5 +39,5 @@
".next/types/**/*.ts", ".next/types/**/*.ts",
"env.js" "env.js"
, "next.config.mjs" ], , "next.config.mjs" ],
"exclude": ["node_modules", "dokploy", "config", "dist","webpack.config.server.js"] "exclude": ["node_modules", "dokploy", "config", "dist","webpack.config.server.js","migration.ts","setup.ts"]
} }