Skip to content

Commit 7ae3ff2

Browse files
authored
Merge pull request #1613 from TheoD02/feat/github-triggerType
feat(github): add triggerType field to GitHub provider and handle tag creation events
2 parents fa6baa0 + bb5c6be commit 7ae3ff2

File tree

12 files changed

+5753
-117
lines changed

12 files changed

+5753
-117
lines changed

apps/dokploy/__test__/drop/drop.test.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const baseApp: ApplicationNested = {
3636
watchPaths: [],
3737
enableSubmodules: false,
3838
applicationStatus: "done",
39+
triggerType: "push",
3940
appName: "",
4041
autoDeploy: true,
4142
serverId: "",

apps/dokploy/__test__/traefik/traefik.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const baseApp: ApplicationNested = {
2525
buildArgs: null,
2626
isPreviewDeploymentsActive: false,
2727
previewBuildArgs: null,
28+
triggerType: "push",
2829
previewCertificateType: "none",
2930
previewEnv: null,
3031
previewHttps: false,

apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx

Lines changed: 105 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const GithubProviderSchema = z.object({
5858
branch: z.string().min(1, "Branch is required"),
5959
githubId: z.string().min(1, "Github Provider is required"),
6060
watchPaths: z.array(z.string()).optional(),
61+
triggerType: z.enum(["push", "tag"]).default("push"),
6162
enableSubmodules: z.boolean().default(false),
6263
});
6364

@@ -83,13 +84,15 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
8384
},
8485
githubId: "",
8586
branch: "",
87+
triggerType: "push",
8688
enableSubmodules: false,
8789
},
8890
resolver: zodResolver(GithubProviderSchema),
8991
});
9092

9193
const repository = form.watch("repository");
9294
const githubId = form.watch("githubId");
95+
const triggerType = form.watch("triggerType");
9396

9497
const { data: repositories, isLoading: isLoadingRepositories } =
9598
api.github.getGithubRepositories.useQuery(
@@ -127,6 +130,7 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
127130
buildPath: data.buildPath || "/",
128131
githubId: data.githubId || "",
129132
watchPaths: data.watchPaths || [],
133+
triggerType: data.triggerType || "push",
130134
enableSubmodules: data.enableSubmodules ?? false,
131135
});
132136
}
@@ -141,6 +145,7 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
141145
buildPath: data.buildPath,
142146
githubId: data.githubId,
143147
watchPaths: data.watchPaths || [],
148+
triggerType: data.triggerType,
144149
enableSubmodules: data.enableSubmodules,
145150
})
146151
.then(async () => {
@@ -386,83 +391,126 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {
386391
/>
387392
<FormField
388393
control={form.control}
389-
name="watchPaths"
394+
name="triggerType"
390395
render={({ field }) => (
391396
<FormItem className="md:col-span-2">
392-
<div className="flex items-center gap-2">
393-
<FormLabel>Watch Paths</FormLabel>
397+
<div className="flex items-center gap-2 ">
398+
<FormLabel>Trigger Type</FormLabel>
394399
<TooltipProvider>
395400
<Tooltip>
396401
<TooltipTrigger asChild>
397402
<HelpCircle className="size-4 text-muted-foreground hover:text-foreground transition-colors cursor-pointer" />
398403
</TooltipTrigger>
399404
<TooltipContent>
400405
<p>
401-
Add paths to watch for changes. When files in these
402-
paths change, a new deployment will be triggered.
406+
Choose when to trigger deployments: on push to the
407+
selected branch or when a new tag is created.
403408
</p>
404409
</TooltipContent>
405410
</Tooltip>
406411
</TooltipProvider>
407412
</div>
408-
<div className="flex flex-wrap gap-2 mb-2">
409-
{field.value?.map((path, index) => (
410-
<Badge
411-
key={index}
412-
variant="secondary"
413-
className="flex items-center gap-1"
414-
>
415-
{path}
416-
<X
417-
className="size-3 cursor-pointer hover:text-destructive"
418-
onClick={() => {
419-
const newPaths = [...(field.value || [])];
420-
newPaths.splice(index, 1);
421-
field.onChange(newPaths);
422-
}}
423-
/>
424-
</Badge>
425-
))}
426-
</div>
427-
<div className="flex gap-2">
413+
<Select
414+
onValueChange={field.onChange}
415+
defaultValue={field.value}
416+
value={field.value}
417+
>
428418
<FormControl>
429-
<Input
430-
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
431-
onKeyDown={(e) => {
432-
if (e.key === "Enter") {
433-
e.preventDefault();
434-
const input = e.currentTarget;
435-
const path = input.value.trim();
436-
if (path) {
437-
field.onChange([...(field.value || []), path]);
438-
input.value = "";
439-
}
440-
}
441-
}}
442-
/>
419+
<SelectTrigger>
420+
<SelectValue placeholder="Select a trigger type" />
421+
</SelectTrigger>
443422
</FormControl>
444-
<Button
445-
type="button"
446-
variant="outline"
447-
size="icon"
448-
onClick={() => {
449-
const input = document.querySelector(
450-
'input[placeholder*="Enter a path"]',
451-
) as HTMLInputElement;
452-
const path = input.value.trim();
453-
if (path) {
454-
field.onChange([...(field.value || []), path]);
455-
input.value = "";
456-
}
457-
}}
458-
>
459-
<Plus className="size-4" />
460-
</Button>
461-
</div>
423+
<SelectContent>
424+
<SelectItem value="push">On Push</SelectItem>
425+
<SelectItem value="tag">On Tag</SelectItem>
426+
</SelectContent>
427+
</Select>
462428
<FormMessage />
463429
</FormItem>
464430
)}
465431
/>
432+
{triggerType === "push" && (
433+
<FormField
434+
control={form.control}
435+
name="watchPaths"
436+
render={({ field }) => (
437+
<FormItem className="md:col-span-2">
438+
<div className="flex items-center gap-2">
439+
<FormLabel>Watch Paths</FormLabel>
440+
<TooltipProvider>
441+
<Tooltip>
442+
<TooltipTrigger asChild>
443+
<HelpCircle className="size-4 text-muted-foreground hover:text-foreground transition-colors cursor-pointer" />
444+
</TooltipTrigger>
445+
<TooltipContent>
446+
<p>
447+
Add paths to watch for changes. When files in
448+
these paths change, a new deployment will be
449+
triggered.
450+
</p>
451+
</TooltipContent>
452+
</Tooltip>
453+
</TooltipProvider>
454+
</div>
455+
<div className="flex flex-wrap gap-2 mb-2">
456+
{field.value?.map((path, index) => (
457+
<Badge
458+
key={index}
459+
variant="secondary"
460+
className="flex items-center gap-1"
461+
>
462+
{path}
463+
<X
464+
className="size-3 cursor-pointer hover:text-destructive"
465+
onClick={() => {
466+
const newPaths = [...(field.value || [])];
467+
newPaths.splice(index, 1);
468+
field.onChange(newPaths);
469+
}}
470+
/>
471+
</Badge>
472+
))}
473+
</div>
474+
<div className="flex gap-2">
475+
<FormControl>
476+
<Input
477+
placeholder="Enter a path to watch (e.g., src/*, dist/*)"
478+
onKeyDown={(e) => {
479+
if (e.key === "Enter") {
480+
e.preventDefault();
481+
const input = e.currentTarget;
482+
const path = input.value.trim();
483+
if (path) {
484+
field.onChange([...(field.value || []), path]);
485+
input.value = "";
486+
}
487+
}
488+
}}
489+
/>
490+
</FormControl>
491+
<Button
492+
type="button"
493+
variant="outline"
494+
size="icon"
495+
onClick={() => {
496+
const input = document.querySelector(
497+
'input[placeholder*="Enter a path"]',
498+
) as HTMLInputElement;
499+
const path = input.value.trim();
500+
if (path) {
501+
field.onChange([...(field.value || []), path]);
502+
input.value = "";
503+
}
504+
}}
505+
>
506+
<Plus className="size-4" />
507+
</Button>
508+
</div>
509+
<FormMessage />
510+
</FormItem>
511+
)}
512+
/>
513+
)}
466514

467515
<FormField
468516
control={form.control}

0 commit comments

Comments
 (0)