mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-06 19:46:44 +03:00
279 lines
7.1 KiB
TypeScript
279 lines
7.1 KiB
TypeScript
import type { GitOrg, MembershipRole } from "@/types/organizations";
|
|
import type { GitRepo, RepoStatus } from "@/types/Repository";
|
|
import { Octokit } from "@octokit/rest";
|
|
import type { Config } from "@/types/config";
|
|
|
|
/**
|
|
* Creates an authenticated Octokit instance
|
|
*/
|
|
export function createGitHubClient(token: string): Octokit {
|
|
return new Octokit({
|
|
auth: token,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Clone a repository from GitHub
|
|
*/
|
|
export async function getGithubRepoCloneUrl({
|
|
octokit,
|
|
owner,
|
|
repo,
|
|
}: {
|
|
octokit: Octokit;
|
|
owner: string;
|
|
repo: string;
|
|
}): Promise<{ url: string; cloneUrl: string }> {
|
|
const { data } = await octokit.repos.get({
|
|
owner,
|
|
repo,
|
|
});
|
|
|
|
return {
|
|
url: data.html_url,
|
|
cloneUrl: data.clone_url,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get user repositories from GitHub
|
|
* todo: need to handle pagination and apply more filters based on user config
|
|
*/
|
|
export async function getGithubRepositories({
|
|
octokit,
|
|
config,
|
|
}: {
|
|
octokit: Octokit;
|
|
config: Partial<Config>;
|
|
}): Promise<GitRepo[]> {
|
|
try {
|
|
const repos = await octokit.paginate(
|
|
octokit.repos.listForAuthenticatedUser,
|
|
{ per_page: 100 }
|
|
);
|
|
|
|
const skipForks = config.githubConfig?.skipForks ?? false;
|
|
|
|
const filteredRepos = repos.filter((repo) => {
|
|
const isForkAllowed = !skipForks || !repo.fork;
|
|
return isForkAllowed;
|
|
});
|
|
|
|
return filteredRepos.map((repo) => ({
|
|
name: repo.name,
|
|
fullName: repo.full_name,
|
|
url: repo.html_url,
|
|
cloneUrl: repo.clone_url,
|
|
|
|
owner: repo.owner.login,
|
|
organization:
|
|
repo.owner.type === "Organization" ? repo.owner.login : undefined,
|
|
|
|
isPrivate: repo.private,
|
|
isForked: repo.fork,
|
|
forkedFrom: (repo as typeof repo & { parent?: { full_name: string } })
|
|
.parent?.full_name,
|
|
|
|
hasIssues: repo.has_issues,
|
|
isStarred: false,
|
|
isArchived: repo.archived,
|
|
|
|
size: repo.size,
|
|
hasLFS: false,
|
|
hasSubmodules: false,
|
|
|
|
defaultBranch: repo.default_branch,
|
|
visibility: (repo.visibility ?? "public") as GitRepo["visibility"],
|
|
|
|
status: "imported",
|
|
lastMirrored: undefined,
|
|
errorMessage: undefined,
|
|
|
|
createdAt: repo.created_at ? new Date(repo.created_at) : new Date(),
|
|
updatedAt: repo.updated_at ? new Date(repo.updated_at) : new Date(),
|
|
}));
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Error fetching repositories: ${
|
|
error instanceof Error ? error.message : String(error)
|
|
}`
|
|
);
|
|
}
|
|
}
|
|
|
|
export async function getGithubStarredRepositories({
|
|
octokit,
|
|
config,
|
|
}: {
|
|
octokit: Octokit;
|
|
config: Partial<Config>;
|
|
}) {
|
|
try {
|
|
const starredRepos = await octokit.paginate(
|
|
octokit.activity.listReposStarredByAuthenticatedUser,
|
|
{
|
|
per_page: 100,
|
|
}
|
|
);
|
|
|
|
return starredRepos.map((repo) => ({
|
|
name: repo.name,
|
|
fullName: repo.full_name,
|
|
url: repo.html_url,
|
|
cloneUrl: repo.clone_url,
|
|
|
|
owner: repo.owner.login,
|
|
organization:
|
|
repo.owner.type === "Organization" ? repo.owner.login : undefined,
|
|
|
|
isPrivate: repo.private,
|
|
isForked: repo.fork,
|
|
forkedFrom: undefined,
|
|
|
|
hasIssues: repo.has_issues,
|
|
isStarred: true,
|
|
isArchived: repo.archived,
|
|
|
|
size: repo.size,
|
|
hasLFS: false, // Placeholder
|
|
hasSubmodules: false, // Placeholder
|
|
|
|
defaultBranch: repo.default_branch,
|
|
visibility: (repo.visibility ?? "public") as GitRepo["visibility"],
|
|
|
|
status: "imported",
|
|
lastMirrored: undefined,
|
|
errorMessage: undefined,
|
|
|
|
createdAt: repo.created_at ? new Date(repo.created_at) : new Date(),
|
|
updatedAt: repo.updated_at ? new Date(repo.updated_at) : new Date(),
|
|
}));
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Error fetching starred repositories: ${
|
|
error instanceof Error ? error.message : String(error)
|
|
}`
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get user github organizations
|
|
*/
|
|
export async function getGithubOrganizations({
|
|
octokit,
|
|
config,
|
|
}: {
|
|
octokit: Octokit;
|
|
config: Partial<Config>;
|
|
}): Promise<GitOrg[]> {
|
|
try {
|
|
const { data: orgs } = await octokit.orgs.listForAuthenticatedUser({
|
|
per_page: 100,
|
|
});
|
|
|
|
// Get excluded organizations from environment variable
|
|
const excludedOrgsEnv = process.env.GITHUB_EXCLUDED_ORGS;
|
|
const excludedOrgs = excludedOrgsEnv
|
|
? excludedOrgsEnv.split(',').map(org => org.trim().toLowerCase())
|
|
: [];
|
|
|
|
// Filter out excluded organizations
|
|
const filteredOrgs = orgs.filter(org => {
|
|
if (excludedOrgs.includes(org.login.toLowerCase())) {
|
|
console.log(`Skipping organization ${org.login} - excluded via GITHUB_EXCLUDED_ORGS environment variable`);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
const organizations = await Promise.all(
|
|
filteredOrgs.map(async (org) => {
|
|
const [{ data: orgDetails }, { data: membership }] = await Promise.all([
|
|
octokit.orgs.get({ org: org.login }),
|
|
octokit.orgs.getMembershipForAuthenticatedUser({ org: org.login }),
|
|
]);
|
|
|
|
const totalRepos =
|
|
orgDetails.public_repos + (orgDetails.total_private_repos ?? 0);
|
|
|
|
return {
|
|
name: org.login,
|
|
avatarUrl: org.avatar_url,
|
|
membershipRole: membership.role as MembershipRole,
|
|
isIncluded: false,
|
|
status: "imported" as RepoStatus,
|
|
repositoryCount: totalRepos,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
};
|
|
})
|
|
);
|
|
|
|
return organizations;
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Error fetching organizations: ${
|
|
error instanceof Error ? error.message : String(error)
|
|
}`
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get repositories for a specific organization
|
|
*/
|
|
export async function getGithubOrganizationRepositories({
|
|
octokit,
|
|
organizationName,
|
|
}: {
|
|
octokit: Octokit;
|
|
organizationName: string;
|
|
}): Promise<GitRepo[]> {
|
|
try {
|
|
const repos = await octokit.paginate(octokit.repos.listForOrg, {
|
|
org: organizationName,
|
|
per_page: 100,
|
|
});
|
|
|
|
return repos.map((repo) => ({
|
|
name: repo.name,
|
|
fullName: repo.full_name,
|
|
url: repo.html_url,
|
|
cloneUrl: repo.clone_url ?? "",
|
|
|
|
owner: repo.owner.login,
|
|
organization: repo.owner.login,
|
|
|
|
isPrivate: repo.private,
|
|
isForked: repo.fork,
|
|
forkedFrom: (repo as typeof repo & { parent?: { full_name: string } })
|
|
.parent?.full_name,
|
|
|
|
hasIssues: repo.has_issues ?? false,
|
|
isStarred: false, // Organization starred repos are separate API
|
|
isArchived: repo.archived ?? false,
|
|
|
|
size: repo.size ?? 0,
|
|
hasLFS: false,
|
|
hasSubmodules: false,
|
|
|
|
defaultBranch: repo.default_branch ?? "main",
|
|
visibility: (repo.visibility ?? "public") as GitRepo["visibility"],
|
|
|
|
status: "imported",
|
|
lastMirrored: undefined,
|
|
errorMessage: undefined,
|
|
|
|
createdAt: repo.created_at ? new Date(repo.created_at) : new Date(),
|
|
updatedAt: repo.updated_at ? new Date(repo.updated_at) : new Date(),
|
|
}));
|
|
} catch (error) {
|
|
throw new Error(
|
|
`Error fetching organization repositories: ${
|
|
error instanceof Error ? error.message : String(error)
|
|
}`
|
|
);
|
|
}
|
|
}
|