mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
feat: add clone by gitlab, github and bitbucket
This commit is contained in:
@@ -11,11 +11,13 @@ import {
|
|||||||
getBitbucketProvider,
|
getBitbucketProvider,
|
||||||
getGitlabProvider,
|
getGitlabProvider,
|
||||||
haveGithubRequirements,
|
haveGithubRequirements,
|
||||||
haveGitlabRequirements,
|
|
||||||
removeGithubProvider,
|
removeGithubProvider,
|
||||||
updateGitlabProvider,
|
|
||||||
} from "../services/git-provider";
|
} from "../services/git-provider";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import {
|
||||||
|
haveGitlabRequirements,
|
||||||
|
refreshGitlabToken,
|
||||||
|
} from "@/server/utils/providers/gitlab";
|
||||||
|
|
||||||
export const gitProvider = createTRPCRouter({
|
export const gitProvider = createTRPCRouter({
|
||||||
getAll: protectedProcedure.query(async () => {
|
getAll: protectedProcedure.query(async () => {
|
||||||
@@ -164,8 +166,7 @@ export const gitProvider = createTRPCRouter({
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
console.log(input);
|
if (!input.gitlabProviderId) {
|
||||||
if (!input.gitlabProviderId || !input.repo || !input.owner) {
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,47 +330,6 @@ export const gitProvider = createTRPCRouter({
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
async function refreshGitlabToken(gitlabProviderId: string) {
|
|
||||||
const gitlabProvider = await getGitlabProvider(gitlabProviderId);
|
|
||||||
const currentTime = Math.floor(Date.now() / 1000);
|
|
||||||
|
|
||||||
const safetyMargin = 60;
|
|
||||||
if (
|
|
||||||
gitlabProvider.expiresAt &&
|
|
||||||
currentTime + safetyMargin < gitlabProvider.expiresAt
|
|
||||||
) {
|
|
||||||
console.log("Token still valid, no need to refresh");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch("https://gitlab.com/oauth/token", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
},
|
|
||||||
body: new URLSearchParams({
|
|
||||||
grant_type: "refresh_token",
|
|
||||||
refresh_token: gitlabProvider.refreshToken as string,
|
|
||||||
client_id: gitlabProvider.applicationId as string,
|
|
||||||
client_secret: gitlabProvider.secret as string,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`Failed to refresh token: ${response.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
const expiresAt = Math.floor(Date.now() / 1000) + data.expires_in;
|
|
||||||
|
|
||||||
await updateGitlabProvider(gitlabProviderId, {
|
|
||||||
accessToken: data.access_token,
|
|
||||||
refreshToken: data.refresh_token,
|
|
||||||
expiresAt,
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
// 1725175543
|
// 1725175543
|
||||||
// {
|
// {
|
||||||
// access_token: '11d422887d8fac712191ee9b09dfdb043a705938cd67a4a39f36b4bc65b3106d',
|
// access_token: '11d422887d8fac712191ee9b09dfdb043a705938cd67a4a39f36b4bc65b3106d',
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import { createDeployment, updateDeploymentStatus } from "./deployment";
|
|||||||
import { sendBuildErrorNotifications } from "@/server/utils/notifications/build-error";
|
import { sendBuildErrorNotifications } from "@/server/utils/notifications/build-error";
|
||||||
import { sendBuildSuccessNotifications } from "@/server/utils/notifications/build-success";
|
import { sendBuildSuccessNotifications } from "@/server/utils/notifications/build-success";
|
||||||
import { validUniqueServerAppName } from "./project";
|
import { validUniqueServerAppName } from "./project";
|
||||||
|
import { cloneGitlabRepository } from "@/server/utils/providers/gitlab";
|
||||||
|
import { cloneBitbucketRepository } from "@/server/utils/providers/bitbucket";
|
||||||
export type Application = typeof applications.$inferSelect;
|
export type Application = typeof applications.$inferSelect;
|
||||||
|
|
||||||
export const createApplication = async (
|
export const createApplication = async (
|
||||||
@@ -81,6 +83,9 @@ export const findApplicationById = async (applicationId: string) => {
|
|||||||
security: true,
|
security: true,
|
||||||
ports: true,
|
ports: true,
|
||||||
registry: true,
|
registry: true,
|
||||||
|
gitlabProvider: true,
|
||||||
|
githubProvider: true,
|
||||||
|
bitbucketProvider: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!application) {
|
if (!application) {
|
||||||
@@ -150,7 +155,13 @@ export const deployApplication = async ({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (application.sourceType === "github") {
|
if (application.sourceType === "github") {
|
||||||
await cloneGithubRepository(admin, application, deployment.logPath);
|
await cloneGithubRepository(application, deployment.logPath);
|
||||||
|
await buildApplication(application, deployment.logPath);
|
||||||
|
} else if (application.sourceType === "gitlab") {
|
||||||
|
await cloneGitlabRepository(application, deployment.logPath);
|
||||||
|
await buildApplication(application, deployment.logPath);
|
||||||
|
} else if (application.sourceType === "bitbucket") {
|
||||||
|
await cloneBitbucketRepository(application, deployment.logPath);
|
||||||
await buildApplication(application, deployment.logPath);
|
await buildApplication(application, deployment.logPath);
|
||||||
} else if (application.sourceType === "docker") {
|
} else if (application.sourceType === "docker") {
|
||||||
await buildDocker(application, deployment.logPath);
|
await buildDocker(application, deployment.logPath);
|
||||||
@@ -214,6 +225,10 @@ export const rebuildApplication = async ({
|
|||||||
try {
|
try {
|
||||||
if (application.sourceType === "github") {
|
if (application.sourceType === "github") {
|
||||||
await buildApplication(application, deployment.logPath);
|
await buildApplication(application, deployment.logPath);
|
||||||
|
} else if (application.sourceType === "gitlab") {
|
||||||
|
await buildApplication(application, deployment.logPath);
|
||||||
|
} else if (application.sourceType === "bitbucket") {
|
||||||
|
await buildApplication(application, deployment.logPath);
|
||||||
} else if (application.sourceType === "docker") {
|
} else if (application.sourceType === "docker") {
|
||||||
await buildDocker(application, deployment.logPath);
|
await buildDocker(application, deployment.logPath);
|
||||||
} else if (application.sourceType === "git") {
|
} else if (application.sourceType === "git") {
|
||||||
|
|||||||
@@ -142,10 +142,6 @@ export const haveGithubRequirements = (githubProvider: GithubProvider) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const haveGitlabRequirements = (gitlabProvider: GitlabProvider) => {
|
|
||||||
return !!(gitlabProvider?.accessToken && gitlabProvider?.refreshToken);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getGitlabProvider = async (gitlabProviderId: string) => {
|
export const getGitlabProvider = async (gitlabProviderId: string) => {
|
||||||
const gitlabProviderResult = await db.query.gitlabProvider.findFirst({
|
const gitlabProviderResult = await db.query.gitlabProvider.findFirst({
|
||||||
where: eq(gitlabProvider.gitlabProviderId, gitlabProviderId),
|
where: eq(gitlabProvider.gitlabProviderId, gitlabProviderId),
|
||||||
|
|||||||
110
apps/dokploy/server/utils/providers/bitbucket.ts
Normal file
110
apps/dokploy/server/utils/providers/bitbucket.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import { createWriteStream } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { APPLICATIONS_PATH, COMPOSE_PATH } from "@/server/constants";
|
||||||
|
import { TRPCError } from "@trpc/server";
|
||||||
|
import { recreateDirectory } from "../filesystem/directory";
|
||||||
|
import { spawnAsync } from "../process/spawnAsync";
|
||||||
|
import type { InferResultType } from "@/server/types/with";
|
||||||
|
|
||||||
|
export type ApplicationWithBitbucket = InferResultType<
|
||||||
|
"applications",
|
||||||
|
{ bitbucketProvider: true }
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const cloneBitbucketRepository = async (
|
||||||
|
entity: ApplicationWithBitbucket,
|
||||||
|
logPath: string,
|
||||||
|
isCompose = false,
|
||||||
|
) => {
|
||||||
|
const writeStream = createWriteStream(logPath, { flags: "a" });
|
||||||
|
const {
|
||||||
|
appName,
|
||||||
|
bitbucketRepository,
|
||||||
|
bitbucketOwner,
|
||||||
|
bitbucketBranch,
|
||||||
|
bitbucketProviderId,
|
||||||
|
bitbucketProvider,
|
||||||
|
} = entity;
|
||||||
|
|
||||||
|
if (!bitbucketProviderId) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "Bitbucket Provider not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
|
||||||
|
const outputPath = join(basePath, appName, "code");
|
||||||
|
await recreateDirectory(outputPath);
|
||||||
|
const repoclone = `bitbucket.org/${bitbucketOwner}/${bitbucketRepository}.git`;
|
||||||
|
const cloneUrl = `https://${bitbucketProvider?.bitbucketUsername}:${bitbucketProvider?.appPassword}@${repoclone}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
writeStream.write(`\nCloning Repo ${repoclone} to ${outputPath}: ✅\n`);
|
||||||
|
await spawnAsync(
|
||||||
|
"git",
|
||||||
|
[
|
||||||
|
"clone",
|
||||||
|
"--branch",
|
||||||
|
bitbucketBranch!,
|
||||||
|
"--depth",
|
||||||
|
"1",
|
||||||
|
cloneUrl,
|
||||||
|
outputPath,
|
||||||
|
"--progress",
|
||||||
|
],
|
||||||
|
(data) => {
|
||||||
|
if (writeStream.writable) {
|
||||||
|
writeStream.write(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
writeStream.write(`\nCloned ${repoclone} to ${outputPath}: ✅\n`);
|
||||||
|
} catch (error) {
|
||||||
|
writeStream.write(`ERROR Clonning: ${error}: ❌`);
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
writeStream.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const cloneRawBitbucketRepository = async (
|
||||||
|
entity: ApplicationWithBitbucket,
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
appName,
|
||||||
|
bitbucketRepository,
|
||||||
|
bitbucketOwner,
|
||||||
|
bitbucketBranch,
|
||||||
|
bitbucketProviderId,
|
||||||
|
bitbucketProvider,
|
||||||
|
} = entity;
|
||||||
|
|
||||||
|
if (!bitbucketProviderId) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "Bitbucket Provider not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const basePath = COMPOSE_PATH;
|
||||||
|
const outputPath = join(basePath, appName, "code");
|
||||||
|
await recreateDirectory(outputPath);
|
||||||
|
const repoclone = `bitbucket.org/${bitbucketOwner}/${bitbucketRepository}.git`;
|
||||||
|
const cloneUrl = `https://${bitbucketProvider?.bitbucketUsername}:${bitbucketProvider?.appPassword}@${repoclone}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await spawnAsync("git", [
|
||||||
|
"clone",
|
||||||
|
"--branch",
|
||||||
|
bitbucketBranch!,
|
||||||
|
"--depth",
|
||||||
|
"1",
|
||||||
|
cloneUrl,
|
||||||
|
outputPath,
|
||||||
|
"--progress",
|
||||||
|
]);
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
import { createWriteStream } from "node:fs";
|
import { createWriteStream } from "node:fs";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { type Admin, findAdmin } from "@/server/api/services/admin";
|
|
||||||
import { APPLICATIONS_PATH, COMPOSE_PATH } from "@/server/constants";
|
import { APPLICATIONS_PATH, COMPOSE_PATH } from "@/server/constants";
|
||||||
import { createAppAuth } from "@octokit/auth-app";
|
import { createAppAuth } from "@octokit/auth-app";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
import { Octokit } from "octokit";
|
import { Octokit } from "octokit";
|
||||||
import { recreateDirectory } from "../filesystem/directory";
|
import { recreateDirectory } from "../filesystem/directory";
|
||||||
import { spawnAsync } from "../process/spawnAsync";
|
import { spawnAsync } from "../process/spawnAsync";
|
||||||
|
import type { InferResultType } from "@/server/types/with";
|
||||||
|
import {
|
||||||
|
getGithubProvider,
|
||||||
|
type GithubProvider,
|
||||||
|
} from "@/server/api/services/git-provider";
|
||||||
|
|
||||||
export const authGithub = (admin: Admin) => {
|
export const authGithub = (githubProvider: GithubProvider) => {
|
||||||
if (!haveGithubRequirements(admin)) {
|
if (!haveGithubRequirements(githubProvider)) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "NOT_FOUND",
|
code: "NOT_FOUND",
|
||||||
message: "Github Account not configured correctly",
|
message: "Github Account not configured correctly",
|
||||||
@@ -19,9 +23,9 @@ export const authGithub = (admin: Admin) => {
|
|||||||
const octokit = new Octokit({
|
const octokit = new Octokit({
|
||||||
authStrategy: createAppAuth,
|
authStrategy: createAppAuth,
|
||||||
auth: {
|
auth: {
|
||||||
appId: admin?.githubAppId || 0,
|
appId: githubProvider?.githubAppId || 0,
|
||||||
privateKey: admin?.githubPrivateKey || "",
|
privateKey: githubProvider?.githubPrivateKey || "",
|
||||||
installationId: admin?.githubInstallationId,
|
installationId: githubProvider?.githubInstallationId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -40,11 +44,11 @@ export const getGithubToken = async (
|
|||||||
return installation.token;
|
return installation.token;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const haveGithubRequirements = (admin: Admin) => {
|
export const haveGithubRequirements = (githubProvider: GithubProvider) => {
|
||||||
return !!(
|
return !!(
|
||||||
admin?.githubAppId &&
|
githubProvider?.githubAppId &&
|
||||||
admin?.githubPrivateKey &&
|
githubProvider?.githubPrivateKey &&
|
||||||
admin?.githubInstallationId
|
githubProvider?.githubInstallationId
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,19 +67,24 @@ const getErrorCloneRequirements = (entity: {
|
|||||||
return reasons;
|
return reasons;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApplicationWithGithub = InferResultType<
|
||||||
|
"applications",
|
||||||
|
{ githubProvider: true }
|
||||||
|
>;
|
||||||
export const cloneGithubRepository = async (
|
export const cloneGithubRepository = async (
|
||||||
admin: Admin,
|
entity: ApplicationWithGithub,
|
||||||
entity: {
|
|
||||||
appName: string;
|
|
||||||
repository?: string | null;
|
|
||||||
owner?: string | null;
|
|
||||||
branch?: string | null;
|
|
||||||
},
|
|
||||||
logPath: string,
|
logPath: string,
|
||||||
isCompose = false,
|
isCompose = false,
|
||||||
) => {
|
) => {
|
||||||
const writeStream = createWriteStream(logPath, { flags: "a" });
|
const writeStream = createWriteStream(logPath, { flags: "a" });
|
||||||
const { appName, repository, owner, branch } = entity;
|
const { appName, repository, owner, branch, githubProviderId } = entity;
|
||||||
|
|
||||||
|
if (!githubProviderId) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "GitHub Provider not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const requirements = getErrorCloneRequirements(entity);
|
const requirements = getErrorCloneRequirements(entity);
|
||||||
|
|
||||||
@@ -92,9 +101,11 @@ export const cloneGithubRepository = async (
|
|||||||
message: "Error: GitHub repository information is incomplete.",
|
message: "Error: GitHub repository information is incomplete.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const githubProvider = await getGithubProvider(githubProviderId);
|
||||||
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");
|
||||||
const octokit = authGithub(admin);
|
const octokit = authGithub(githubProvider);
|
||||||
const token = await getGithubToken(octokit);
|
const token = await getGithubToken(octokit);
|
||||||
const repoclone = `github.com/${owner}/${repository}.git`;
|
const repoclone = `github.com/${owner}/${repository}.git`;
|
||||||
await recreateDirectory(outputPath);
|
await recreateDirectory(outputPath);
|
||||||
@@ -129,17 +140,21 @@ export const cloneGithubRepository = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cloneRawGithubRepository = async (entity: {
|
export const cloneRawGithubRepository = async (
|
||||||
appName: string;
|
entity: ApplicationWithGithub,
|
||||||
repository?: string | null;
|
) => {
|
||||||
owner?: string | null;
|
const { appName, repository, owner, branch, githubProviderId } = entity;
|
||||||
branch?: string | null;
|
|
||||||
}) => {
|
if (!githubProviderId) {
|
||||||
const { appName, repository, owner, branch } = entity;
|
throw new TRPCError({
|
||||||
const admin = await findAdmin();
|
code: "NOT_FOUND",
|
||||||
|
message: "GitHub Provider not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const githubProvider = await getGithubProvider(githubProviderId);
|
||||||
const basePath = COMPOSE_PATH;
|
const basePath = COMPOSE_PATH;
|
||||||
const outputPath = join(basePath, appName, "code");
|
const outputPath = join(basePath, appName, "code");
|
||||||
const octokit = authGithub(admin);
|
const octokit = authGithub(githubProvider);
|
||||||
const token = await getGithubToken(octokit);
|
const token = await getGithubToken(octokit);
|
||||||
const repoclone = `github.com/${owner}/${repository}.git`;
|
const repoclone = `github.com/${owner}/${repository}.git`;
|
||||||
await recreateDirectory(outputPath);
|
await recreateDirectory(outputPath);
|
||||||
|
|||||||
194
apps/dokploy/server/utils/providers/gitlab.ts
Normal file
194
apps/dokploy/server/utils/providers/gitlab.ts
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
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";
|
||||||
|
import { spawnAsync } from "../process/spawnAsync";
|
||||||
|
import {
|
||||||
|
getGitlabProvider,
|
||||||
|
type GitlabProvider,
|
||||||
|
updateGitlabProvider,
|
||||||
|
} from "@/server/api/services/git-provider";
|
||||||
|
import type { InferResultType } from "@/server/types/with";
|
||||||
|
|
||||||
|
export const refreshGitlabToken = async (gitlabProviderId: string) => {
|
||||||
|
const gitlabProvider = await getGitlabProvider(gitlabProviderId);
|
||||||
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
|
const safetyMargin = 60;
|
||||||
|
if (
|
||||||
|
gitlabProvider.expiresAt &&
|
||||||
|
currentTime + safetyMargin < gitlabProvider.expiresAt
|
||||||
|
) {
|
||||||
|
console.log("Token still valid, no need to refresh");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch("https://gitlab.com/oauth/token", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
grant_type: "refresh_token",
|
||||||
|
refresh_token: gitlabProvider.refreshToken as string,
|
||||||
|
client_id: gitlabProvider.applicationId as string,
|
||||||
|
client_secret: gitlabProvider.secret as string,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to refresh token: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
const expiresAt = Math.floor(Date.now() / 1000) + data.expires_in;
|
||||||
|
|
||||||
|
await updateGitlabProvider(gitlabProviderId, {
|
||||||
|
accessToken: data.access_token,
|
||||||
|
refreshToken: data.refresh_token,
|
||||||
|
expiresAt,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const haveGitlabRequirements = (gitlabProvider: GitlabProvider) => {
|
||||||
|
return !!(gitlabProvider?.accessToken && gitlabProvider?.refreshToken);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getErrorCloneRequirements = (entity: {
|
||||||
|
repository?: string | null;
|
||||||
|
owner?: string | null;
|
||||||
|
branch?: string | null;
|
||||||
|
}) => {
|
||||||
|
const reasons: string[] = [];
|
||||||
|
const { repository, owner, branch } = entity;
|
||||||
|
|
||||||
|
if (!repository) reasons.push("1. Repository not assigned.");
|
||||||
|
if (!owner) reasons.push("2. Owner not specified.");
|
||||||
|
if (!branch) reasons.push("3. Branch not defined.");
|
||||||
|
|
||||||
|
return reasons;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ApplicationWithGitlab = InferResultType<
|
||||||
|
"applications",
|
||||||
|
{ gitlabProvider: true }
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const cloneGitlabRepository = async (
|
||||||
|
entity: ApplicationWithGitlab,
|
||||||
|
logPath: string,
|
||||||
|
isCompose = false,
|
||||||
|
) => {
|
||||||
|
const writeStream = createWriteStream(logPath, { flags: "a" });
|
||||||
|
const {
|
||||||
|
appName,
|
||||||
|
gitlabRepository,
|
||||||
|
gitlabOwner,
|
||||||
|
gitlabBranch,
|
||||||
|
gitlabProviderId,
|
||||||
|
gitlabProvider,
|
||||||
|
} = entity;
|
||||||
|
|
||||||
|
if (!gitlabProviderId) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "Gitlab Provider not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await refreshGitlabToken(gitlabProviderId);
|
||||||
|
|
||||||
|
const requirements = getErrorCloneRequirements(entity);
|
||||||
|
|
||||||
|
// Check if requirements are met
|
||||||
|
if (requirements.length > 0) {
|
||||||
|
writeStream.write(
|
||||||
|
`\nGitLab Repository configuration failed for application: ${appName}\n`,
|
||||||
|
);
|
||||||
|
writeStream.write("Reasons:\n");
|
||||||
|
writeStream.write(requirements.join("\n"));
|
||||||
|
writeStream.end();
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "BAD_REQUEST",
|
||||||
|
message: "Error: GitLab repository information is incomplete.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const basePath = isCompose ? COMPOSE_PATH : APPLICATIONS_PATH;
|
||||||
|
const outputPath = join(basePath, appName, "code");
|
||||||
|
await recreateDirectory(outputPath);
|
||||||
|
const repoclone = `gitlab.com/${gitlabOwner}/${gitlabRepository}.git`;
|
||||||
|
const cloneUrl = `https://oauth2:${gitlabProvider?.accessToken}@${repoclone}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
writeStream.write(`\nClonning Repo ${repoclone} to ${outputPath}: ✅\n`);
|
||||||
|
await spawnAsync(
|
||||||
|
"git",
|
||||||
|
[
|
||||||
|
"clone",
|
||||||
|
"--branch",
|
||||||
|
gitlabBranch!,
|
||||||
|
"--depth",
|
||||||
|
"1",
|
||||||
|
cloneUrl,
|
||||||
|
outputPath,
|
||||||
|
"--progress",
|
||||||
|
],
|
||||||
|
(data) => {
|
||||||
|
if (writeStream.writable) {
|
||||||
|
writeStream.write(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
writeStream.write(`\nCloned ${repoclone}: ✅\n`);
|
||||||
|
} catch (error) {
|
||||||
|
writeStream.write(`ERROR Clonning: ${error}: ❌`);
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
writeStream.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const cloneRawGitlabRepository = async (
|
||||||
|
entity: ApplicationWithGitlab,
|
||||||
|
) => {
|
||||||
|
const {
|
||||||
|
appName,
|
||||||
|
gitlabRepository,
|
||||||
|
gitlabOwner,
|
||||||
|
gitlabBranch,
|
||||||
|
gitlabProviderId,
|
||||||
|
gitlabProvider,
|
||||||
|
} = entity;
|
||||||
|
|
||||||
|
if (!gitlabProviderId) {
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "Gitlab Provider not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await refreshGitlabToken(gitlabProviderId);
|
||||||
|
const basePath = COMPOSE_PATH;
|
||||||
|
const outputPath = join(basePath, appName, "code");
|
||||||
|
await recreateDirectory(outputPath);
|
||||||
|
const repoclone = `gitlab.com/${gitlabOwner}/${gitlabRepository}.git`;
|
||||||
|
const cloneUrl = `https://oauth2:${gitlabProvider?.accessToken}@${repoclone}`;
|
||||||
|
try {
|
||||||
|
await spawnAsync("git", [
|
||||||
|
"clone",
|
||||||
|
"--branch",
|
||||||
|
gitlabBranch!,
|
||||||
|
"--depth",
|
||||||
|
"1",
|
||||||
|
cloneUrl,
|
||||||
|
outputPath,
|
||||||
|
"--progress",
|
||||||
|
]);
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user