From ed46fd3cef69773636ee335fd0abe897bd7a3489 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 1 Sep 2024 00:32:25 -0600 Subject: [PATCH] refactor: split logic to utils files --- .../server/api/routers/git-provider.ts | 271 ++---------------- .../server/utils/providers/bitbucket.ts | 109 +++++++ apps/dokploy/server/utils/providers/github.ts | 60 ++++ apps/dokploy/server/utils/providers/gitlab.ts | 100 ++++++- 4 files changed, 284 insertions(+), 256 deletions(-) diff --git a/apps/dokploy/server/api/routers/git-provider.ts b/apps/dokploy/server/api/routers/git-provider.ts index 44e255ebf..6203aca8e 100644 --- a/apps/dokploy/server/api/routers/git-provider.ts +++ b/apps/dokploy/server/api/routers/git-provider.ts @@ -9,19 +9,23 @@ import { TRPCError } from "@trpc/server"; import { createBitbucketProvider, createGitlabProvider, - getBitbucketProvider, - getGithubProvider, - getGitlabProvider, haveGithubRequirements, removeGithubProvider, } from "../services/git-provider"; import { z } from "zod"; import { + getGitlabBranches, + getGitlabRepositories, haveGitlabRequirements, - refreshGitlabToken, } from "@/server/utils/providers/gitlab"; -import { Octokit } from "octokit"; -import { createAppAuth } from "@octokit/auth-app"; +import { + getBitbucketBranches, + getBitbucketRepositories, +} from "@/server/utils/providers/bitbucket"; +import { + getGithubBranches, + getGithubRepositories, +} from "@/server/utils/providers/github"; export const gitProvider = createTRPCRouter({ getAll: protectedProcedure.query(async () => { @@ -129,36 +133,7 @@ export const gitProvider = createTRPCRouter({ }), ) .query(async ({ input }) => { - if (!input.gitlabProviderId) { - return []; - } - await refreshGitlabToken(input.gitlabProviderId); - - const gitlabProvider = await getGitlabProvider(input.gitlabProviderId); - const response = await fetch( - `https://gitlab.com/api/v4/projects?membership=true&owned=true&page=${0}&per_page=${100}`, - { - headers: { - Authorization: `Bearer ${gitlabProvider.accessToken}`, - }, - }, - ); - - if (!response.ok) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: `Failed to fetch repositories: ${response.statusText}`, - }); - } - - const repositories = await response.json(); - return repositories as { - name: string; - url: string; - owner: { - username: string; - }; - }[]; + return await getGitlabRepositories(input); }), getGitlabBranches: protectedProcedure @@ -170,60 +145,7 @@ export const gitProvider = createTRPCRouter({ }), ) .query(async ({ input }) => { - if (!input.gitlabProviderId) { - return []; - } - - const gitlabProvider = await getGitlabProvider(input.gitlabProviderId); - - const projectResponse = await fetch( - `https://gitlab.com/api/v4/projects?search=${input.repo}&owned=true&page=1&per_page=100`, - { - headers: { - Authorization: `Bearer ${gitlabProvider.accessToken}`, - }, - }, - ); - - if (!projectResponse.ok) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: `Failed to fetch repositories: ${projectResponse.statusText}`, - }); - } - - const projects = await projectResponse.json(); - const project = projects.find( - (p) => p.namespace.path === input.owner && p.name === input.repo, - ); - - if (!project) { - throw new Error(`Project not found: ${input.owner}/${input.repo}`); - } - - const branchesResponse = await fetch( - `https://gitlab.com/api/v4/projects/${project.id}/repository/branches`, - { - headers: { - Authorization: `Bearer ${gitlabProvider.accessToken}`, - }, - }, - ); - - if (!branchesResponse.ok) { - throw new Error( - `Failed to fetch branches: ${branchesResponse.statusText}`, - ); - } - - const branches = await branchesResponse.json(); - - return branches as { - name: string; - commit: { - id: string; - }; - }[]; + return await getGitlabBranches(input); }), getBitbucketRepositories: protectedProcedure .input( @@ -232,52 +154,7 @@ export const gitProvider = createTRPCRouter({ }), ) .query(async ({ input }) => { - if (!input.bitbucketProviderId) { - return []; - } - const bitbucketProvider = await getBitbucketProvider( - input.bitbucketProviderId, - ); - - const url = `https://api.bitbucket.org/2.0/repositories/${bitbucketProvider.bitbucketUsername}`; - - try { - const response = await fetch(url, { - method: "GET", - headers: { - Authorization: `Basic ${Buffer.from(`${bitbucketProvider.bitbucketUsername}:${bitbucketProvider.appPassword}`).toString("base64")}`, - }, - }); - - if (!response.ok) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: `Failed to fetch repositories: ${response.statusText}`, - }); - } - - const data = await response.json(); - - const mappedData = data.values.map((repo) => { - return { - name: repo.name, - url: repo.links.html.href, - owner: { - username: repo.workspace.slug, - }, - }; - }); - - return mappedData as { - name: string; - url: string; - owner: { - username: string; - }; - }[]; - } catch (error) { - throw error; - } + return await getBitbucketRepositories(input); }), getBitbucketBranches: protectedProcedure .input( @@ -288,50 +165,7 @@ export const gitProvider = createTRPCRouter({ }), ) .query(async ({ input }) => { - if (!input.bitbucketProviderId) { - return []; - } - const bitbucketProvider = await getBitbucketProvider( - input.bitbucketProviderId, - ); - const { owner, repo } = input; - const url = `https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/refs/branches`; - - try { - const response = await fetch(url, { - method: "GET", - headers: { - Authorization: `Basic ${Buffer.from(`${bitbucketProvider.bitbucketUsername}:${bitbucketProvider.appPassword}`).toString("base64")}`, - }, - }); - - if (!response.ok) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: `HTTP error! status: ${response.status}`, - }); - } - - const data = await response.json(); - - const mappedData = data.values.map((branch) => { - return { - name: branch.name, - commit: { - sha: branch.target.hash, - }, - }; - }); - - return mappedData as { - name: string; - commit: { - sha: string; - }; - }[]; - } catch (error) { - throw error; - } + return await getBitbucketBranches(input); }), getRepositories: protectedProcedure .input( @@ -340,84 +174,11 @@ export const gitProvider = createTRPCRouter({ }), ) .query(async ({ input }) => { - if (!input.githubProviderId) { - return []; - } - - const githubProvider = await getGithubProvider(input.githubProviderId); - - const octokit = new Octokit({ - authStrategy: createAppAuth, - auth: { - appId: githubProvider.githubAppId, - privateKey: githubProvider.githubPrivateKey, - installationId: githubProvider.githubInstallationId, - }, - }); - - const repositories = (await octokit.paginate( - octokit.rest.apps.listReposAccessibleToInstallation, - )) as unknown as Awaited< - ReturnType - >["data"]["repositories"]; - - return repositories; + return await getGithubRepositories(input); }), getBranches: protectedProcedure .input(apiGetBranches) .query(async ({ input }) => { - // const admin = await findAdmin(); - - // const completeRequirements = haveGithubRequirements(admin); - - // if (!completeRequirements) { - // throw new TRPCError({ - // code: "BAD_REQUEST", - // message: "Admin need to setup correctly github account", - // }); - // } - - if (!input.githubProviderId) { - return []; - } - const githubProvider = await getGithubProvider(input.githubProviderId); - - const octokit = new Octokit({ - authStrategy: createAppAuth, - auth: { - appId: githubProvider.githubAppId, - privateKey: githubProvider.githubPrivateKey, - installationId: githubProvider.githubInstallationId, - }, - }); - - const branches = (await octokit.paginate( - octokit.rest.repos.listBranches, - { - owner: input.owner, - repo: input.repo, - }, - )) as unknown as Awaited< - ReturnType - >["data"]; - - return branches; + return await getGithubBranches(input); }), }); -// 1725175543 -// { -// access_token: '11d422887d8fac712191ee9b09dfdb043a705938cd67a4a39f36b4bc65b3106d', -// token_type: 'Bearer', -// expires_in: 7200, -// refresh_token: '3806d8022d32886c19d91eb9d1cea9328b864387f39c5d0469d08c48e18b674e', -// scope: 'api read_user read_repository', -// created_at: 1725167656 -// } -// { -// access_token: 'd256b52b10bf72ebf2784f8c0528e48a04a7d249c28695b6cc105b47b09c7336', -// token_type: 'Bearer', -// expires_in: 7200, -// refresh_token: '265eb87d0bbef410e0c30a2c239c4fa3698943219a439fb43cf2f8227d1fcaf2', -// scope: 'api read_user read_repository', -// created_at: 1725167803 -// } diff --git a/apps/dokploy/server/utils/providers/bitbucket.ts b/apps/dokploy/server/utils/providers/bitbucket.ts index 04529120e..d5c888820 100644 --- a/apps/dokploy/server/utils/providers/bitbucket.ts +++ b/apps/dokploy/server/utils/providers/bitbucket.ts @@ -5,6 +5,7 @@ import { TRPCError } from "@trpc/server"; import { recreateDirectory } from "../filesystem/directory"; import { spawnAsync } from "../process/spawnAsync"; import type { InferResultType } from "@/server/types/with"; +import { getBitbucketProvider } from "@/server/api/services/git-provider"; export type ApplicationWithBitbucket = InferResultType< "applications", @@ -108,3 +109,111 @@ export const cloneRawBitbucketRepository = async ( throw error; } }; + +interface GetBitbucketRepositories { + bitbucketProviderId?: string; +} + +export const getBitbucketRepositories = async ( + input: GetBitbucketRepositories, +) => { + if (!input.bitbucketProviderId) { + return []; + } + const bitbucketProvider = await getBitbucketProvider( + input.bitbucketProviderId, + ); + + const url = `https://api.bitbucket.org/2.0/repositories/${bitbucketProvider.bitbucketUsername}`; + + try { + const response = await fetch(url, { + method: "GET", + headers: { + Authorization: `Basic ${Buffer.from(`${bitbucketProvider.bitbucketUsername}:${bitbucketProvider.appPassword}`).toString("base64")}`, + }, + }); + + if (!response.ok) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: `Failed to fetch repositories: ${response.statusText}`, + }); + } + + const data = await response.json(); + + const mappedData = data.values.map((repo) => { + return { + name: repo.name, + url: repo.links.html.href, + owner: { + username: repo.workspace.slug, + }, + }; + }); + + return mappedData as { + name: string; + url: string; + owner: { + username: string; + }; + }[]; + } catch (error) { + throw error; + } +}; + +interface GetBitbucketBranches { + owner: string; + repo: string; + bitbucketProviderId?: string; +} + +export const getBitbucketBranches = async (input: GetBitbucketBranches) => { + if (!input.bitbucketProviderId) { + return []; + } + const bitbucketProvider = await getBitbucketProvider( + input.bitbucketProviderId, + ); + const { owner, repo } = input; + const url = `https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/refs/branches`; + + try { + const response = await fetch(url, { + method: "GET", + headers: { + Authorization: `Basic ${Buffer.from(`${bitbucketProvider.bitbucketUsername}:${bitbucketProvider.appPassword}`).toString("base64")}`, + }, + }); + + if (!response.ok) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: `HTTP error! status: ${response.status}`, + }); + } + + const data = await response.json(); + + const mappedData = data.values.map((branch) => { + return { + name: branch.name, + commit: { + sha: branch.target.hash, + }, + }; + }); + + return mappedData as { + name: string; + commit: { + sha: string; + }; + }[]; + } catch (error) { + throw error; + } +}; diff --git a/apps/dokploy/server/utils/providers/github.ts b/apps/dokploy/server/utils/providers/github.ts index 6a693a801..e1ec5cde6 100644 --- a/apps/dokploy/server/utils/providers/github.ts +++ b/apps/dokploy/server/utils/providers/github.ts @@ -174,3 +174,63 @@ export const cloneRawGithubRepository = async ( throw error; } }; + +interface GetGithubRepositories { + githubProviderId?: string; +} + +export const getGithubRepositories = async (input: GetGithubRepositories) => { + if (!input.githubProviderId) { + return []; + } + + const githubProvider = await getGithubProvider(input.githubProviderId); + + const octokit = new Octokit({ + authStrategy: createAppAuth, + auth: { + appId: githubProvider.githubAppId, + privateKey: githubProvider.githubPrivateKey, + installationId: githubProvider.githubInstallationId, + }, + }); + + const repositories = (await octokit.paginate( + octokit.rest.apps.listReposAccessibleToInstallation, + )) as unknown as Awaited< + ReturnType + >["data"]["repositories"]; + + return repositories; +}; + +interface GetGithubBranches { + owner: string; + repo: string; + githubProviderId?: string; +} + +export const getGithubBranches = async (input: GetGithubBranches) => { + if (!input.githubProviderId) { + return []; + } + const githubProvider = await getGithubProvider(input.githubProviderId); + + const octokit = new Octokit({ + authStrategy: createAppAuth, + auth: { + appId: githubProvider.githubAppId, + privateKey: githubProvider.githubPrivateKey, + installationId: githubProvider.githubInstallationId, + }, + }); + + const branches = (await octokit.paginate(octokit.rest.repos.listBranches, { + owner: input.owner, + repo: input.repo, + })) as unknown as Awaited< + ReturnType + >["data"]; + + return branches; +}; diff --git a/apps/dokploy/server/utils/providers/gitlab.ts b/apps/dokploy/server/utils/providers/gitlab.ts index 927d60fa7..b63f367a6 100644 --- a/apps/dokploy/server/utils/providers/gitlab.ts +++ b/apps/dokploy/server/utils/providers/gitlab.ts @@ -1,6 +1,5 @@ import { createWriteStream } from "node:fs"; import { join } from "node:path"; -import { findAdmin } from "@/server/api/services/admin"; import { APPLICATIONS_PATH, COMPOSE_PATH } from "@/server/constants"; import { TRPCError } from "@trpc/server"; import { recreateDirectory } from "../filesystem/directory"; @@ -152,6 +151,105 @@ export const cloneGitlabRepository = async ( } }; +interface GetGitlabRepositories { + gitlabProviderId?: string; +} + +export const getGitlabRepositories = async (input: GetGitlabRepositories) => { + if (!input.gitlabProviderId) { + return []; + } + + await refreshGitlabToken(input.gitlabProviderId); + + const gitlabProvider = await getGitlabProvider(input.gitlabProviderId); + const response = await fetch( + `https://gitlab.com/api/v4/projects?membership=true&owned=true&page=${0}&per_page=${100}`, + { + headers: { + Authorization: `Bearer ${gitlabProvider.accessToken}`, + }, + }, + ); + + if (!response.ok) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: `Failed to fetch repositories: ${response.statusText}`, + }); + } + + const repositories = await response.json(); + return repositories as { + name: string; + url: string; + owner: { + username: string; + }; + }[]; +}; + +interface GetGitlabBranches { + owner: string; + repo: string; + gitlabProviderId?: string; +} + +export const getGitlabBranches = async (input: GetGitlabBranches) => { + if (!input.gitlabProviderId) { + return []; + } + + const gitlabProvider = await getGitlabProvider(input.gitlabProviderId); + + const projectResponse = await fetch( + `https://gitlab.com/api/v4/projects?search=${input.repo}&owned=true&page=1&per_page=100`, + { + headers: { + Authorization: `Bearer ${gitlabProvider.accessToken}`, + }, + }, + ); + + if (!projectResponse.ok) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: `Failed to fetch repositories: ${projectResponse.statusText}`, + }); + } + + const projects = await projectResponse.json(); + const project = projects.find( + (p) => p.namespace.path === input.owner && p.name === input.repo, + ); + + if (!project) { + throw new Error(`Project not found: ${input.owner}/${input.repo}`); + } + + const branchesResponse = await fetch( + `https://gitlab.com/api/v4/projects/${project.id}/repository/branches`, + { + headers: { + Authorization: `Bearer ${gitlabProvider.accessToken}`, + }, + }, + ); + + if (!branchesResponse.ok) { + throw new Error(`Failed to fetch branches: ${branchesResponse.statusText}`); + } + + const branches = await branchesResponse.json(); + + return branches as { + name: string; + commit: { + id: string; + }; + }[]; +}; + export const cloneRawGitlabRepository = async ( entity: ApplicationWithGitlab, ) => {