3.1.0 - Added Gitea integration for Projects page
All checks were successful
Docker Deploy / build-and-push (push) Successful in 4m25s
All checks were successful
Docker Deploy / build-and-push (push) Successful in 4m25s
This commit is contained in:
145
src/utils/gitea.ts
Normal file
145
src/utils/gitea.ts
Normal file
@@ -0,0 +1,145 @@
|
||||
export interface GiteaRepoInfo {
|
||||
commits: number;
|
||||
releases: number;
|
||||
language: string;
|
||||
updatedAt: string;
|
||||
size: number;
|
||||
defaultBranch: string;
|
||||
topics: string[];
|
||||
}
|
||||
|
||||
export interface GiteaConfig {
|
||||
domain: string;
|
||||
owner: string;
|
||||
repo: string;
|
||||
}
|
||||
|
||||
export function parseGiteaUrl(url: string): GiteaConfig | null {
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
const pathParts = urlObj.pathname.split("/").filter((p) => p);
|
||||
|
||||
if (pathParts.length >= 2) {
|
||||
return {
|
||||
domain: urlObj.origin,
|
||||
owner: pathParts[0],
|
||||
repo: pathParts[1],
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
// Invalid URL
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function fetchGiteaRepoInfo(
|
||||
config: GiteaConfig,
|
||||
): Promise<GiteaRepoInfo | null> {
|
||||
try {
|
||||
const apiUrl = `${config.domain}/api/v1/repos/${config.owner}/${config.repo}`;
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
let commitsCount = 0;
|
||||
try {
|
||||
const commitsUrl = `${config.domain}/api/v1/repos/${config.owner}/${config.repo}/commits?limit=1&stat=false`;
|
||||
const commitsResponse = await fetch(commitsUrl, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
if (commitsResponse.ok) {
|
||||
const totalCount = commitsResponse.headers.get("X-Total-Count");
|
||||
commitsCount = totalCount ? parseInt(totalCount, 10) : 0;
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
let releasesCount = 0;
|
||||
try {
|
||||
const releasesUrl = `${config.domain}/api/v1/repos/${config.owner}/${config.repo}/releases`;
|
||||
const releasesResponse = await fetch(releasesUrl, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
if (releasesResponse.ok) {
|
||||
const releases = await releasesResponse.json();
|
||||
releasesCount = Array.isArray(releases) ? releases.length : 0;
|
||||
}
|
||||
} catch (error) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
return {
|
||||
commits: commitsCount,
|
||||
releases: releasesCount,
|
||||
language: data.language || "Unknown",
|
||||
updatedAt: data.updated_at || data.pushed_at || "",
|
||||
size: data.size || 0,
|
||||
defaultBranch: data.default_branch || "main",
|
||||
topics: Array.isArray(data.topics) ? data.topics : [],
|
||||
};
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchGiteaInfoFromUrl(
|
||||
url: string,
|
||||
): Promise<GiteaRepoInfo | null> {
|
||||
const config = parseGiteaUrl(url);
|
||||
if (!config) {
|
||||
return null;
|
||||
}
|
||||
return fetchGiteaRepoInfo(config);
|
||||
}
|
||||
|
||||
export function formatRelativeTime(dateString: string): string {
|
||||
if (!dateString) return "Unknown";
|
||||
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diffMs = now.getTime() - date.getTime();
|
||||
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
||||
const diffMinutes = Math.floor(diffMs / (1000 * 60));
|
||||
|
||||
if (diffMinutes < 60) {
|
||||
return `${diffMinutes} minute${diffMinutes !== 1 ? "s" : ""} ago`;
|
||||
} else if (diffHours < 24) {
|
||||
return `${diffHours} hour${diffHours !== 1 ? "s" : ""} ago`;
|
||||
} else if (diffDays < 30) {
|
||||
return `${diffDays} day${diffDays !== 1 ? "s" : ""} ago`;
|
||||
} else if (diffDays < 365) {
|
||||
const months = Math.floor(diffDays / 30);
|
||||
return `${months} month${months !== 1 ? "s" : ""} ago`;
|
||||
} else {
|
||||
const years = Math.floor(diffDays / 365);
|
||||
return `${years} year${years !== 1 ? "s" : ""} ago`;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatRepoSize(sizeKb: number): string {
|
||||
if (sizeKb < 1024) {
|
||||
return `${sizeKb} KB`;
|
||||
} else if (sizeKb < 1024 * 1024) {
|
||||
return `${(sizeKb / 1024).toFixed(1)} MB`;
|
||||
} else {
|
||||
return `${(sizeKb / (1024 * 1024)).toFixed(1)} GB`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user