mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat: compose app
This commit is contained in:
parent
1f81ebd4fe
commit
c681aa2e9f
@ -1,4 +1,3 @@
|
|||||||
import { AddSSHKey } from "@/components/dashboard/settings/ssh-keys/add-ssh-key";
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
@ -20,13 +19,10 @@ import {
|
|||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { SelectSeparator } from "@radix-ui/react-select";
|
|
||||||
import { KeyRoundIcon, LockIcon } from "lucide-react";
|
import { KeyRoundIcon, LockIcon } from "lucide-react";
|
||||||
import Link from "next/link";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { flushSync } from "react-dom";
|
|
||||||
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";
|
||||||
@ -53,11 +49,7 @@ export const SaveGitProvider = ({ applicationId }: Props) => {
|
|||||||
|
|
||||||
const { mutateAsync, isLoading } =
|
const { mutateAsync, isLoading } =
|
||||||
api.application.saveGitProdiver.useMutation();
|
api.application.saveGitProdiver.useMutation();
|
||||||
// const { mutateAsync: generateSSHKey, isLoading: isGeneratingSSHKey } =
|
|
||||||
// api.application.generateSSHKey.useMutation();
|
|
||||||
|
|
||||||
// const { mutateAsync: removeSSHKey, isLoading: isRemovingSSHKey } =
|
|
||||||
// api.application.removeSSHKey.useMutation();
|
|
||||||
const form = useForm<GitProvider>({
|
const form = useForm<GitProvider>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
branch: "",
|
branch: "",
|
||||||
@ -152,7 +144,6 @@ export const SaveGitProvider = ({ applicationId }: Props) => {
|
|||||||
<SelectItem value="none">None</SelectItem>
|
<SelectItem value="none">None</SelectItem>
|
||||||
<SelectLabel>Keys ({sshKeys?.length})</SelectLabel>
|
<SelectLabel>Keys ({sshKeys?.length})</SelectLabel>
|
||||||
</SelectGroup>
|
</SelectGroup>
|
||||||
<SelectSeparator />
|
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
@ -1,13 +1,4 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
|
||||||
Dialog,
|
|
||||||
DialogContent,
|
|
||||||
DialogDescription,
|
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
|
||||||
DialogTitle,
|
|
||||||
DialogTrigger,
|
|
||||||
} from "@/components/ui/dialog";
|
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
@ -17,11 +8,19 @@ import {
|
|||||||
FormMessage,
|
FormMessage,
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
|
SelectItem,
|
||||||
|
SelectLabel,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import copy from "copy-to-clipboard";
|
import { KeyRoundIcon, LockIcon } from "lucide-react";
|
||||||
import { CopyIcon, LockIcon } from "lucide-react";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@ -33,6 +32,7 @@ const GitProviderSchema = z.object({
|
|||||||
message: "Repository URL is required",
|
message: "Repository URL is required",
|
||||||
}),
|
}),
|
||||||
branch: z.string().min(1, "Branch required"),
|
branch: z.string().min(1, "Branch required"),
|
||||||
|
sshKey: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
type GitProvider = z.infer<typeof GitProviderSchema>;
|
type GitProvider = z.infer<typeof GitProviderSchema>;
|
||||||
@ -43,19 +43,17 @@ interface Props {
|
|||||||
|
|
||||||
export const SaveGitProviderCompose = ({ composeId }: Props) => {
|
export const SaveGitProviderCompose = ({ composeId }: Props) => {
|
||||||
const { data, refetch } = api.compose.one.useQuery({ composeId });
|
const { data, refetch } = api.compose.one.useQuery({ composeId });
|
||||||
|
const { data: sshKeys } = api.sshKey.all.useQuery();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const { mutateAsync, isLoading } = api.compose.update.useMutation();
|
const { mutateAsync, isLoading } = api.compose.update.useMutation();
|
||||||
|
|
||||||
const { mutateAsync: generateSSHKey, isLoading: isGeneratingSSHKey } =
|
|
||||||
api.compose.generateSSHKey.useMutation();
|
|
||||||
|
|
||||||
const { mutateAsync: removeSSHKey, isLoading: isRemovingSSHKey } =
|
|
||||||
api.compose.removeSSHKey.useMutation();
|
|
||||||
const form = useForm<GitProvider>({
|
const form = useForm<GitProvider>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
branch: "",
|
branch: "",
|
||||||
repositoryURL: "",
|
repositoryURL: "",
|
||||||
composePath: "./docker-compose.yml",
|
composePath: "./docker-compose.yml",
|
||||||
|
sshKey: undefined,
|
||||||
},
|
},
|
||||||
resolver: zodResolver(GitProviderSchema),
|
resolver: zodResolver(GitProviderSchema),
|
||||||
});
|
});
|
||||||
@ -63,6 +61,7 @@ export const SaveGitProviderCompose = ({ composeId }: Props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
form.reset({
|
form.reset({
|
||||||
|
sshKey: data.customGitSSHKeyId || undefined,
|
||||||
branch: data.customGitBranch || "",
|
branch: data.customGitBranch || "",
|
||||||
repositoryURL: data.customGitUrl || "",
|
repositoryURL: data.customGitUrl || "",
|
||||||
composePath: data.composePath,
|
composePath: data.composePath,
|
||||||
@ -74,6 +73,7 @@ export const SaveGitProviderCompose = ({ composeId }: Props) => {
|
|||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
customGitBranch: values.branch,
|
customGitBranch: values.branch,
|
||||||
customGitUrl: values.repositoryURL,
|
customGitUrl: values.repositoryURL,
|
||||||
|
customGitSSHKeyId: values.sshKey === "none" ? null : values.sshKey,
|
||||||
composeId,
|
composeId,
|
||||||
sourceType: "git",
|
sourceType: "git",
|
||||||
composePath: values.composePath,
|
composePath: values.composePath,
|
||||||
@ -94,123 +94,72 @@ export const SaveGitProviderCompose = ({ composeId }: Props) => {
|
|||||||
className="flex flex-col gap-4"
|
className="flex flex-col gap-4"
|
||||||
>
|
>
|
||||||
<div className="grid md:grid-cols-2 gap-4 ">
|
<div className="grid md:grid-cols-2 gap-4 ">
|
||||||
<div className="md:col-span-2 space-y-4">
|
<div className="flex items-end col-span-2 gap-4">
|
||||||
<FormField
|
<div className="grow">
|
||||||
control={form.control}
|
<FormField
|
||||||
name="repositoryURL"
|
control={form.control}
|
||||||
render={({ field }) => (
|
name="repositoryURL"
|
||||||
<FormItem>
|
render={({ field }) => (
|
||||||
<FormLabel className="flex flex-row justify-between">
|
<FormItem>
|
||||||
Repository URL
|
<FormLabel className="flex flex-row justify-between">
|
||||||
<div className="flex gap-2">
|
Repository URL
|
||||||
<Dialog>
|
</FormLabel>
|
||||||
<DialogTrigger className="flex flex-row gap-2">
|
<FormControl>
|
||||||
<LockIcon className="size-4 text-muted-foreground" />?
|
<Input placeholder="git@bitbucket.org" {...field} />
|
||||||
</DialogTrigger>
|
</FormControl>
|
||||||
<DialogContent className="sm:max-w-[425px]">
|
<FormMessage />
|
||||||
<DialogHeader>
|
</FormItem>
|
||||||
<DialogTitle>Private Repository</DialogTitle>
|
)}
|
||||||
<DialogDescription>
|
/>
|
||||||
If your repository is private is necessary to
|
</div>
|
||||||
generate SSH Keys to add to your git provider.
|
{sshKeys && sshKeys.length > 0 ? (
|
||||||
</DialogDescription>
|
<FormField
|
||||||
</DialogHeader>
|
control={form.control}
|
||||||
<div className="grid gap-4 py-4">
|
name="sshKey"
|
||||||
<div className="relative">
|
render={({ field }) => (
|
||||||
<Textarea
|
<FormItem className="basis-40">
|
||||||
placeholder="Please click on Generate SSH Key"
|
<FormLabel className="w-full inline-flex justify-between">
|
||||||
className="no-scrollbar h-64 text-muted-foreground"
|
SSH Key
|
||||||
disabled={!data?.customGitSSHKey}
|
<LockIcon className="size-4 text-muted-foreground" />
|
||||||
contentEditable={false}
|
</FormLabel>
|
||||||
value={
|
<FormControl>
|
||||||
data?.customGitSSHKey ||
|
<Select
|
||||||
"Please click on Generate SSH Key"
|
key={field.value}
|
||||||
}
|
onValueChange={field.onChange}
|
||||||
/>
|
defaultValue={field.value}
|
||||||
<button
|
value={field.value}
|
||||||
type="button"
|
>
|
||||||
className="absolute right-2 top-2"
|
<SelectTrigger>
|
||||||
onClick={() => {
|
<SelectValue placeholder="Select a key" />
|
||||||
copy(
|
</SelectTrigger>
|
||||||
data?.customGitSSHKey ||
|
<SelectContent>
|
||||||
"Generate a SSH Key",
|
<SelectGroup>
|
||||||
);
|
{sshKeys?.map((sshKey) => (
|
||||||
toast.success("SSH Copied to clipboard");
|
<SelectItem
|
||||||
}}
|
key={sshKey.sshKeyId}
|
||||||
|
value={sshKey.sshKeyId}
|
||||||
>
|
>
|
||||||
<CopyIcon className="size-4" />
|
{sshKey.name}
|
||||||
</button>
|
</SelectItem>
|
||||||
</div>
|
))}
|
||||||
</div>
|
<SelectItem value="none">None</SelectItem>
|
||||||
<DialogFooter className="flex sm:justify-between gap-3.5 flex-col sm:flex-col w-full">
|
<SelectLabel>Keys ({sshKeys?.length})</SelectLabel>
|
||||||
<div className="flex flex-row gap-2 w-full justify-between flex-wrap">
|
</SelectGroup>
|
||||||
{data?.customGitSSHKey && (
|
</SelectContent>
|
||||||
<Button
|
</Select>
|
||||||
variant="destructive"
|
</FormControl>
|
||||||
isLoading={
|
</FormItem>
|
||||||
isGeneratingSSHKey || isRemovingSSHKey
|
)}
|
||||||
}
|
/>
|
||||||
className="max-sm:w-full"
|
) : (
|
||||||
onClick={async () => {
|
<Button
|
||||||
await removeSSHKey({
|
variant="secondary"
|
||||||
composeId,
|
onClick={() => router.push("/dashboard/settings/ssh-keys")}
|
||||||
})
|
type="button"
|
||||||
.then(async () => {
|
>
|
||||||
toast.success("SSH Key Removed");
|
<KeyRoundIcon className="size-4" /> Add SSH Key
|
||||||
await refetch();
|
</Button>
|
||||||
})
|
)}
|
||||||
.catch(() => {
|
|
||||||
toast.error(
|
|
||||||
"Error to remove the SSH Key",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Remove SSH Key
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
isLoading={
|
|
||||||
isGeneratingSSHKey || isRemovingSSHKey
|
|
||||||
}
|
|
||||||
className="max-sm:w-full"
|
|
||||||
onClick={async () => {
|
|
||||||
await generateSSHKey({
|
|
||||||
composeId,
|
|
||||||
})
|
|
||||||
.then(async () => {
|
|
||||||
toast.success("SSH Key Generated");
|
|
||||||
await refetch();
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
toast.error(
|
|
||||||
"Error to generate the SSH Key",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Generate SSH Key
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<span className="text-sm text-muted-foreground">
|
|
||||||
Is recommended to remove the SSH Key if you want
|
|
||||||
to deploy a public repository.
|
|
||||||
</span>
|
|
||||||
</DialogFooter>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
|
||||||
</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input placeholder="git@bitbucket.org" {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<FormField
|
<FormField
|
||||||
|
8
drizzle/0027_fantastic_squadron_sinister.sql
Normal file
8
drizzle/0027_fantastic_squadron_sinister.sql
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
ALTER TABLE "compose" ADD COLUMN "customGitSSHKeyId" text;--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "compose" ADD CONSTRAINT "compose_customGitSSHKeyId_ssh-key_sshKeyId_fk" FOREIGN KEY ("customGitSSHKeyId") REFERENCES "public"."ssh-key"("sshKeyId") ON DELETE set null ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "compose" DROP COLUMN IF EXISTS "customGitSSHKey";
|
3010
drizzle/meta/0027_snapshot.json
Normal file
3010
drizzle/meta/0027_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -190,6 +190,13 @@
|
|||||||
"when": 1721928706816,
|
"when": 1721928706816,
|
||||||
"tag": "0026_yielding_king_cobra",
|
"tag": "0026_yielding_king_cobra",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 27,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1721937297064,
|
||||||
|
"tag": "0027_fantastic_squadron_sinister",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -31,11 +31,6 @@ import {
|
|||||||
removeDirectoryCode,
|
removeDirectoryCode,
|
||||||
removeMonitoringDirectory,
|
removeMonitoringDirectory,
|
||||||
} from "@/server/utils/filesystem/directory";
|
} from "@/server/utils/filesystem/directory";
|
||||||
import {
|
|
||||||
generateSSHKey,
|
|
||||||
readSSHPublicKey,
|
|
||||||
removeSSHKey,
|
|
||||||
} from "@/server/utils/filesystem/ssh";
|
|
||||||
import {
|
import {
|
||||||
readConfig,
|
readConfig,
|
||||||
removeTraefikConfig,
|
removeTraefikConfig,
|
||||||
@ -130,7 +125,6 @@ export const applicationRouter = createTRPCRouter({
|
|||||||
async () => await removeMonitoringDirectory(application?.appName),
|
async () => await removeMonitoringDirectory(application?.appName),
|
||||||
async () => await removeTraefikConfig(application?.appName),
|
async () => await removeTraefikConfig(application?.appName),
|
||||||
async () => await removeService(application?.appName),
|
async () => await removeService(application?.appName),
|
||||||
async () => await removeSSHKey(application?.appName),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const operation of cleanupOperations) {
|
for (const operation of cleanupOperations) {
|
||||||
@ -240,32 +234,6 @@ export const applicationRouter = createTRPCRouter({
|
|||||||
applicationStatus: "idle",
|
applicationStatus: "idle",
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
|
||||||
}),
|
|
||||||
generateSSHKey: protectedProcedure
|
|
||||||
.input(apiFindOneApplication)
|
|
||||||
.mutation(async ({ input }) => {
|
|
||||||
const application = await findApplicationById(input.applicationId);
|
|
||||||
try {
|
|
||||||
await generateSSHKey(application.appName);
|
|
||||||
const file = await readSSHPublicKey(application.appName);
|
|
||||||
|
|
||||||
// await updateApplication(input.applicationId, {
|
|
||||||
// customGitSSHKey: file,
|
|
||||||
// });
|
|
||||||
} catch (error) {}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}),
|
|
||||||
removeSSHKey: protectedProcedure
|
|
||||||
.input(apiFindOneApplication)
|
|
||||||
.mutation(async ({ input }) => {
|
|
||||||
const application = await findApplicationById(input.applicationId);
|
|
||||||
await removeSSHKey(application.appName);
|
|
||||||
// await updateApplication(input.applicationId, {
|
|
||||||
// customGitSSHKey: null,
|
|
||||||
// });
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
markRunning: protectedProcedure
|
markRunning: protectedProcedure
|
||||||
|
@ -16,11 +16,6 @@ import { myQueue } from "@/server/queues/queueSetup";
|
|||||||
import { createCommand } from "@/server/utils/builders/compose";
|
import { createCommand } from "@/server/utils/builders/compose";
|
||||||
import { randomizeComposeFile } from "@/server/utils/docker/compose";
|
import { randomizeComposeFile } from "@/server/utils/docker/compose";
|
||||||
import { removeComposeDirectory } from "@/server/utils/filesystem/directory";
|
import { removeComposeDirectory } from "@/server/utils/filesystem/directory";
|
||||||
import {
|
|
||||||
generateSSHKey,
|
|
||||||
readSSHPublicKey,
|
|
||||||
removeSSHKey,
|
|
||||||
} from "@/server/utils/filesystem/ssh";
|
|
||||||
import { templates } from "@/templates/templates";
|
import { templates } from "@/templates/templates";
|
||||||
import type { TemplatesKeys } from "@/templates/types/templates-data.type";
|
import type { TemplatesKeys } from "@/templates/types/templates-data.type";
|
||||||
import {
|
import {
|
||||||
@ -102,7 +97,6 @@ export const composeRouter = createTRPCRouter({
|
|||||||
async () => await removeCompose(composeResult),
|
async () => await removeCompose(composeResult),
|
||||||
async () => await removeDeploymentsByComposeId(composeResult),
|
async () => await removeDeploymentsByComposeId(composeResult),
|
||||||
async () => await removeComposeDirectory(composeResult.appName),
|
async () => await removeComposeDirectory(composeResult.appName),
|
||||||
async () => await removeSSHKey(composeResult.appName),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const operation of cleanupOperations) {
|
for (const operation of cleanupOperations) {
|
||||||
@ -181,38 +175,12 @@ export const composeRouter = createTRPCRouter({
|
|||||||
const command = createCommand(compose);
|
const command = createCommand(compose);
|
||||||
return `docker ${command}`;
|
return `docker ${command}`;
|
||||||
}),
|
}),
|
||||||
generateSSHKey: protectedProcedure
|
|
||||||
.input(apiFindCompose)
|
|
||||||
.mutation(async ({ input }) => {
|
|
||||||
const compose = await findComposeById(input.composeId);
|
|
||||||
try {
|
|
||||||
await generateSSHKey(compose.appName);
|
|
||||||
const file = await readSSHPublicKey(compose.appName);
|
|
||||||
|
|
||||||
await updateCompose(input.composeId, {
|
|
||||||
customGitSSHKey: file,
|
|
||||||
});
|
|
||||||
} catch (error) {}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}),
|
|
||||||
refreshToken: protectedProcedure
|
refreshToken: protectedProcedure
|
||||||
.input(apiFindCompose)
|
.input(apiFindCompose)
|
||||||
.mutation(async ({ input }) => {
|
.mutation(async ({ input }) => {
|
||||||
await updateCompose(input.composeId, {
|
await updateCompose(input.composeId, {
|
||||||
refreshToken: nanoid(),
|
refreshToken: nanoid(),
|
||||||
});
|
});
|
||||||
return true;
|
|
||||||
}),
|
|
||||||
removeSSHKey: protectedProcedure
|
|
||||||
.input(apiFindCompose)
|
|
||||||
.mutation(async ({ input }) => {
|
|
||||||
const compose = await findComposeById(input.composeId);
|
|
||||||
await removeSSHKey(compose.appName);
|
|
||||||
await updateCompose(input.composeId, {
|
|
||||||
customGitSSHKey: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}),
|
}),
|
||||||
deployTemplate: protectedProcedure
|
deployTemplate: protectedProcedure
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { sshKeys } from "@/server/db/schema/ssh-key";
|
||||||
import { generatePassword } from "@/templates/utils";
|
import { generatePassword } from "@/templates/utils";
|
||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { boolean, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
|
import { boolean, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
|
||||||
@ -41,7 +42,12 @@ export const compose = pgTable("compose", {
|
|||||||
// Git
|
// Git
|
||||||
customGitUrl: text("customGitUrl"),
|
customGitUrl: text("customGitUrl"),
|
||||||
customGitBranch: text("customGitBranch"),
|
customGitBranch: text("customGitBranch"),
|
||||||
customGitSSHKey: text("customGitSSHKey"),
|
customGitSSHKeyId: text("customGitSSHKeyId").references(
|
||||||
|
() => sshKeys.sshKeyId,
|
||||||
|
{
|
||||||
|
onDelete: "set null",
|
||||||
|
},
|
||||||
|
),
|
||||||
//
|
//
|
||||||
command: text("command").notNull().default(""),
|
command: text("command").notNull().default(""),
|
||||||
//
|
//
|
||||||
@ -62,6 +68,10 @@ export const composeRelations = relations(compose, ({ one, many }) => ({
|
|||||||
}),
|
}),
|
||||||
deployments: many(deployments),
|
deployments: many(deployments),
|
||||||
mounts: many(mounts),
|
mounts: many(mounts),
|
||||||
|
customGitSSHKey: one(sshKeys, {
|
||||||
|
fields: [compose.customGitSSHKeyId],
|
||||||
|
references: [sshKeys.sshKeyId],
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const createSchema = createInsertSchema(compose, {
|
const createSchema = createInsertSchema(compose, {
|
||||||
@ -70,6 +80,7 @@ const createSchema = createInsertSchema(compose, {
|
|||||||
env: z.string().optional(),
|
env: z.string().optional(),
|
||||||
composeFile: z.string().min(1),
|
composeFile: z.string().min(1),
|
||||||
projectId: z.string(),
|
projectId: z.string(),
|
||||||
|
customGitSSHKeyId: z.string().optional(),
|
||||||
command: z.string().optional(),
|
command: z.string().optional(),
|
||||||
composePath: z.string().min(1),
|
composePath: z.string().min(1),
|
||||||
composeType: z.enum(["docker-compose", "stack"]).optional(),
|
composeType: z.enum(["docker-compose", "stack"]).optional(),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { applications } from "@/server/db/schema/application";
|
import { applications } from "@/server/db/schema/application";
|
||||||
|
import { compose } from "@/server/db/schema/compose";
|
||||||
import { sshKeyCreate } from "@/server/db/validations";
|
import { sshKeyCreate } from "@/server/db/validations";
|
||||||
import { relations } from "drizzle-orm";
|
import { relations } from "drizzle-orm";
|
||||||
import { pgTable, text, time } from "drizzle-orm/pg-core";
|
import { pgTable, text, time } from "drizzle-orm/pg-core";
|
||||||
@ -21,6 +22,7 @@ export const sshKeys = pgTable("ssh-key", {
|
|||||||
|
|
||||||
export const sshKeysRelations = relations(sshKeys, ({ many }) => ({
|
export const sshKeysRelations = relations(sshKeys, ({ many }) => ({
|
||||||
applications: many(applications),
|
applications: many(applications),
|
||||||
|
compose: many(compose),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const createSchema = createInsertSchema(
|
const createSchema = createInsertSchema(
|
||||||
|
@ -39,7 +39,7 @@ export const cloneGitRepository = async (
|
|||||||
writeStream.write(
|
writeStream.write(
|
||||||
`\nCloning Repo Custom ${customGitUrl} to ${outputPath}: ✅\n`,
|
`\nCloning Repo Custom ${customGitUrl} to ${outputPath}: ✅\n`,
|
||||||
);
|
);
|
||||||
console.log(customGitSSHKeyId);
|
|
||||||
await spawnAsync(
|
await spawnAsync(
|
||||||
"git",
|
"git",
|
||||||
[
|
[
|
||||||
|
Loading…
Reference in New Issue
Block a user