mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge pull request #835 from Dokploy/560-self-hosted-gitlab
560 self hosted gitlab
This commit is contained in:
@@ -33,6 +33,9 @@ const Schema = z.object({
|
|||||||
name: z.string().min(1, {
|
name: z.string().min(1, {
|
||||||
message: "Name is required",
|
message: "Name is required",
|
||||||
}),
|
}),
|
||||||
|
gitlabUrl: z.string().min(1, {
|
||||||
|
message: "GitLab URL is required",
|
||||||
|
}),
|
||||||
applicationId: z.string().min(1, {
|
applicationId: z.string().min(1, {
|
||||||
message: "Application ID is required",
|
message: "Application ID is required",
|
||||||
}),
|
}),
|
||||||
@@ -62,16 +65,22 @@ export const AddGitlabProvider = () => {
|
|||||||
applicationSecret: "",
|
applicationSecret: "",
|
||||||
groupName: "",
|
groupName: "",
|
||||||
redirectUri: webhookUrl,
|
redirectUri: webhookUrl,
|
||||||
|
name: "",
|
||||||
|
gitlabUrl: "https://gitlab.com",
|
||||||
},
|
},
|
||||||
resolver: zodResolver(Schema),
|
resolver: zodResolver(Schema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const gitlabUrl = form.watch("gitlabUrl");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form.reset({
|
form.reset({
|
||||||
applicationId: "",
|
applicationId: "",
|
||||||
applicationSecret: "",
|
applicationSecret: "",
|
||||||
groupName: "",
|
groupName: "",
|
||||||
redirectUri: webhookUrl,
|
redirectUri: webhookUrl,
|
||||||
|
name: "",
|
||||||
|
gitlabUrl: "https://gitlab.com",
|
||||||
});
|
});
|
||||||
}, [form, isOpen]);
|
}, [form, isOpen]);
|
||||||
|
|
||||||
@@ -83,6 +92,7 @@ export const AddGitlabProvider = () => {
|
|||||||
authId: auth?.id || "",
|
authId: auth?.id || "",
|
||||||
name: data.name || "",
|
name: data.name || "",
|
||||||
redirectUri: data.redirectUri || "",
|
redirectUri: data.redirectUri || "",
|
||||||
|
gitlabUrl: data.gitlabUrl || "https://gitlab.com",
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
await utils.gitProvider.getAll.invalidate();
|
await utils.gitProvider.getAll.invalidate();
|
||||||
@@ -129,7 +139,7 @@ export const AddGitlabProvider = () => {
|
|||||||
<li className="flex flex-row gap-2 items-center">
|
<li className="flex flex-row gap-2 items-center">
|
||||||
Go to your GitLab profile settings{" "}
|
Go to your GitLab profile settings{" "}
|
||||||
<Link
|
<Link
|
||||||
href="https://gitlab.com/-/profile/applications"
|
href={`${gitlabUrl}/-/profile/applications`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<ExternalLink className="w-fit text-primary size-4" />
|
<ExternalLink className="w-fit text-primary size-4" />
|
||||||
@@ -169,6 +179,20 @@ export const AddGitlabProvider = () => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="gitlabUrl"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Gitlab URL</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="https://gitlab.com/" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="redirectUri"
|
name="redirectUri"
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ const Schema = z.object({
|
|||||||
name: z.string().min(1, {
|
name: z.string().min(1, {
|
||||||
message: "Name is required",
|
message: "Name is required",
|
||||||
}),
|
}),
|
||||||
|
gitlabUrl: z.string().url({
|
||||||
|
message: "Invalid Gitlab URL",
|
||||||
|
}),
|
||||||
groupName: z.string().optional(),
|
groupName: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -40,7 +43,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const EditGitlabProvider = ({ gitlabId }: Props) => {
|
export const EditGitlabProvider = ({ gitlabId }: Props) => {
|
||||||
const { data: gitlab } = api.gitlab.one.useQuery(
|
const { data: gitlab, refetch } = api.gitlab.one.useQuery(
|
||||||
{
|
{
|
||||||
gitlabId,
|
gitlabId,
|
||||||
},
|
},
|
||||||
@@ -57,6 +60,7 @@ export const EditGitlabProvider = ({ gitlabId }: Props) => {
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
groupName: "",
|
groupName: "",
|
||||||
name: "",
|
name: "",
|
||||||
|
gitlabUrl: "https://gitlab.com",
|
||||||
},
|
},
|
||||||
resolver: zodResolver(Schema),
|
resolver: zodResolver(Schema),
|
||||||
});
|
});
|
||||||
@@ -67,6 +71,7 @@ export const EditGitlabProvider = ({ gitlabId }: Props) => {
|
|||||||
form.reset({
|
form.reset({
|
||||||
groupName: gitlab?.groupName || "",
|
groupName: gitlab?.groupName || "",
|
||||||
name: gitlab?.gitProvider.name || "",
|
name: gitlab?.gitProvider.name || "",
|
||||||
|
gitlabUrl: gitlab?.gitlabUrl || "",
|
||||||
});
|
});
|
||||||
}, [form, isOpen]);
|
}, [form, isOpen]);
|
||||||
|
|
||||||
@@ -76,11 +81,13 @@ export const EditGitlabProvider = ({ gitlabId }: Props) => {
|
|||||||
gitProviderId: gitlab?.gitProviderId || "",
|
gitProviderId: gitlab?.gitProviderId || "",
|
||||||
groupName: data.groupName || "",
|
groupName: data.groupName || "",
|
||||||
name: data.name || "",
|
name: data.name || "",
|
||||||
|
gitlabUrl: data.gitlabUrl || "",
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
await utils.gitProvider.getAll.invalidate();
|
await utils.gitProvider.getAll.invalidate();
|
||||||
toast.success("Gitlab updated successfully");
|
toast.success("Gitlab updated successfully");
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
|
refetch();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
toast.error("Error to update Gitlab");
|
toast.error("Error to update Gitlab");
|
||||||
@@ -126,6 +133,19 @@ export const EditGitlabProvider = ({ gitlabId }: Props) => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="gitlabUrl"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>Gitlab Url</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="https://gitlab.com" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
|
|||||||
@@ -23,12 +23,16 @@ export const ShowGitProviders = () => {
|
|||||||
|
|
||||||
const url = useUrl();
|
const url = useUrl();
|
||||||
|
|
||||||
const getGitlabUrl = (clientId: string, gitlabId: string) => {
|
const getGitlabUrl = (
|
||||||
|
clientId: string,
|
||||||
|
gitlabId: string,
|
||||||
|
gitlabUrl: string,
|
||||||
|
) => {
|
||||||
const redirectUri = `${url}/api/providers/gitlab/callback?gitlabId=${gitlabId}`;
|
const redirectUri = `${url}/api/providers/gitlab/callback?gitlabId=${gitlabId}`;
|
||||||
|
|
||||||
const scope = "api read_user read_repository";
|
const scope = "api read_user read_repository";
|
||||||
|
|
||||||
const authUrl = `https://gitlab.com/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scope)}`;
|
const authUrl = `${gitlabUrl}/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${encodeURIComponent(scope)}`;
|
||||||
|
|
||||||
return authUrl;
|
return authUrl;
|
||||||
};
|
};
|
||||||
@@ -142,6 +146,7 @@ export const ShowGitProviders = () => {
|
|||||||
href={getGitlabUrl(
|
href={getGitlabUrl(
|
||||||
gitProvider.gitlab?.applicationId || "",
|
gitProvider.gitlab?.applicationId || "",
|
||||||
gitProvider.gitlab?.gitlabId || "",
|
gitProvider.gitlab?.gitlabId || "",
|
||||||
|
gitProvider.gitlab?.gitlabUrl,
|
||||||
)}
|
)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
|
|||||||
1
apps/dokploy/drizzle/0050_nappy_wrecker.sql
Normal file
1
apps/dokploy/drizzle/0050_nappy_wrecker.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "gitlab" ADD COLUMN "gitlabUrl" text DEFAULT 'https://gitlab.com' NOT NULL;
|
||||||
4233
apps/dokploy/drizzle/meta/0050_snapshot.json
Normal file
4233
apps/dokploy/drizzle/meta/0050_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -351,6 +351,13 @@
|
|||||||
"when": 1733628762978,
|
"when": 1733628762978,
|
||||||
"tag": "0049_dark_leopardon",
|
"tag": "0049_dark_leopardon",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 50,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1733889104203,
|
||||||
|
"tag": "0050_nappy_wrecker",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ export default async function handler(
|
|||||||
|
|
||||||
const gitlab = await findGitlabById(gitlabId as string);
|
const gitlab = await findGitlabById(gitlabId as string);
|
||||||
|
|
||||||
const response = await fetch("https://gitlab.com/oauth/token", {
|
const response = await fetch(`${gitlab.gitlabUrl}/oauth/token`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
|||||||
@@ -142,6 +142,10 @@ export const gitlabRouter = createTRPCRouter({
|
|||||||
name: input.name,
|
name: input.name,
|
||||||
adminId: ctx.user.adminId,
|
adminId: ctx.user.adminId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await updateGitlab(input.gitlabId, {
|
||||||
|
...input,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
await updateGitlab(input.gitlabId, {
|
await updateGitlab(input.gitlabId, {
|
||||||
...input,
|
...input,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const gitlab = pgTable("gitlab", {
|
|||||||
.notNull()
|
.notNull()
|
||||||
.primaryKey()
|
.primaryKey()
|
||||||
.$defaultFn(() => nanoid()),
|
.$defaultFn(() => nanoid()),
|
||||||
|
gitlabUrl: text("gitlabUrl").default("https://gitlab.com").notNull(),
|
||||||
applicationId: text("application_id"),
|
applicationId: text("application_id"),
|
||||||
redirectUri: text("redirect_uri"),
|
redirectUri: text("redirect_uri"),
|
||||||
secret: text("secret"),
|
secret: text("secret"),
|
||||||
@@ -39,6 +40,7 @@ export const apiCreateGitlab = createSchema.extend({
|
|||||||
redirectUri: z.string().optional(),
|
redirectUri: z.string().optional(),
|
||||||
authId: z.string().min(1),
|
authId: z.string().min(1),
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
|
gitlabUrl: z.string().min(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const apiFindOneGitlab = createSchema
|
export const apiFindOneGitlab = createSchema
|
||||||
@@ -67,4 +69,5 @@ export const apiUpdateGitlab = createSchema.extend({
|
|||||||
redirectUri: z.string().optional(),
|
redirectUri: z.string().optional(),
|
||||||
name: z.string().min(1),
|
name: z.string().min(1),
|
||||||
gitlabId: z.string().min(1),
|
gitlabId: z.string().min(1),
|
||||||
|
gitlabUrl: z.string().min(1),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export const refreshGitlabToken = async (gitlabProviderId: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch("https://gitlab.com/oauth/token", {
|
const response = await fetch(`${gitlabProvider.gitlabUrl}/oauth/token`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
@@ -122,7 +122,7 @@ export const cloneGitlabRepository = async (
|
|||||||
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
|
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
|
||||||
const outputPath = join(basePath, appName, "code");
|
const outputPath = join(basePath, appName, "code");
|
||||||
await recreateDirectory(outputPath);
|
await recreateDirectory(outputPath);
|
||||||
const repoclone = `gitlab.com/${gitlabPathNamespace}.git`;
|
const repoclone = `${gitlab?.gitlabUrl.replace(/^https?:\/\//, "")}/${gitlabPathNamespace}.git`;
|
||||||
const cloneUrl = `https://oauth2:${gitlab?.accessToken}@${repoclone}`;
|
const cloneUrl = `https://oauth2:${gitlab?.accessToken}@${repoclone}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -218,7 +218,7 @@ export const getGitlabCloneCommand = async (
|
|||||||
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
|
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
|
||||||
const outputPath = join(basePath, appName, "code");
|
const outputPath = join(basePath, appName, "code");
|
||||||
await recreateDirectory(outputPath);
|
await recreateDirectory(outputPath);
|
||||||
const repoclone = `gitlab.com/${gitlabPathNamespace}.git`;
|
const repoclone = `${gitlab?.gitlabUrl.replace(/^https?:\/\//, "")}/${gitlabPathNamespace}.git`;
|
||||||
const cloneUrl = `https://oauth2:${gitlab?.accessToken}@${repoclone}`;
|
const cloneUrl = `https://oauth2:${gitlab?.accessToken}@${repoclone}`;
|
||||||
|
|
||||||
const cloneCommand = `
|
const cloneCommand = `
|
||||||
@@ -244,7 +244,7 @@ export const getGitlabRepositories = async (gitlabId?: string) => {
|
|||||||
const gitlabProvider = await findGitlabById(gitlabId);
|
const gitlabProvider = await findGitlabById(gitlabId);
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`https://gitlab.com/api/v4/projects?membership=true&owned=true&page=${0}&per_page=${100}`,
|
`${gitlabProvider.gitlabUrl}/api/v4/projects?membership=true&owned=true&page=${0}&per_page=${100}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
||||||
@@ -304,7 +304,7 @@ export const getGitlabBranches = async (input: {
|
|||||||
const gitlabProvider = await findGitlabById(input.gitlabId);
|
const gitlabProvider = await findGitlabById(input.gitlabId);
|
||||||
|
|
||||||
const branchesResponse = await fetch(
|
const branchesResponse = await fetch(
|
||||||
`https://gitlab.com/api/v4/projects/${input.id}/repository/branches`,
|
`${gitlabProvider.gitlabUrl}/api/v4/projects/${input.id}/repository/branches`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
||||||
@@ -350,7 +350,9 @@ export const cloneRawGitlabRepository = async (entity: Compose) => {
|
|||||||
const basePath = COMPOSE_PATH;
|
const basePath = COMPOSE_PATH;
|
||||||
const outputPath = join(basePath, appName, "code");
|
const outputPath = join(basePath, appName, "code");
|
||||||
await recreateDirectory(outputPath);
|
await recreateDirectory(outputPath);
|
||||||
const repoclone = `gitlab.com/${gitlabPathNamespace}.git`;
|
const gitlabUrl = gitlabProvider.gitlabUrl;
|
||||||
|
// What happen with oauth in self hosted instances?
|
||||||
|
const repoclone = `${gitlabUrl.replace(/^https?:\/\//, "")}/${gitlabPathNamespace}.git`;
|
||||||
const cloneUrl = `https://oauth2:${gitlabProvider?.accessToken}@${repoclone}`;
|
const cloneUrl = `https://oauth2:${gitlabProvider?.accessToken}@${repoclone}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -390,7 +392,7 @@ export const cloneRawGitlabRepositoryRemote = async (compose: Compose) => {
|
|||||||
await refreshGitlabToken(gitlabId);
|
await refreshGitlabToken(gitlabId);
|
||||||
const basePath = COMPOSE_PATH;
|
const basePath = COMPOSE_PATH;
|
||||||
const outputPath = join(basePath, appName, "code");
|
const outputPath = join(basePath, appName, "code");
|
||||||
const repoclone = `gitlab.com/${gitlabPathNamespace}.git`;
|
const repoclone = `${gitlabProvider.gitlabUrl.replace(/^https?:\/\//, "")}/${gitlabPathNamespace}.git`;
|
||||||
const cloneUrl = `https://oauth2:${gitlabProvider?.accessToken}@${repoclone}`;
|
const cloneUrl = `https://oauth2:${gitlabProvider?.accessToken}@${repoclone}`;
|
||||||
try {
|
try {
|
||||||
const command = `
|
const command = `
|
||||||
@@ -417,7 +419,7 @@ export const testGitlabConnection = async (
|
|||||||
const gitlabProvider = await findGitlabById(gitlabId);
|
const gitlabProvider = await findGitlabById(gitlabId);
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`https://gitlab.com/api/v4/projects?membership=true&owned=true&page=${0}&per_page=${100}`,
|
`${gitlabProvider.gitlabUrl}/api/v4/projects?membership=true&owned=true&page=${0}&per_page=${100}`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
Authorization: `Bearer ${gitlabProvider.accessToken}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user