All checks were successful
Docker Deploy / build-and-push (push) Successful in 4m25s
146 lines
3.8 KiB
TypeScript
146 lines
3.8 KiB
TypeScript
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`;
|
|
}
|
|
}
|