- GITEA_URL was pointing to gitea.platform.svc but the Helm chart names the HTTP service gitea-helm-http.platform.svc - Add Gitea badge (GT, green) to repo search results UI - Update placeholder and credential hint to mention Gitea - Rewrite internal service URLs to external gitea.coreworlds.io in search results so agents can clone from outside the cluster - Add error logging to diagnose search failures
150 lines
4.1 KiB
TypeScript
150 lines
4.1 KiB
TypeScript
import { getRawCredentialsByProvider } from "./credentials";
|
|
|
|
export interface RepoResult {
|
|
provider: "github" | "gitlab" | "gitea";
|
|
fullName: string;
|
|
url: string;
|
|
description: string;
|
|
defaultBranch: string;
|
|
private: boolean;
|
|
}
|
|
|
|
export async function searchRepos(query: string): Promise<RepoResult[]> {
|
|
if (!query || query.length < 2) return [];
|
|
|
|
const results = await Promise.allSettled([
|
|
searchGitHub(query),
|
|
searchGitLab(query),
|
|
searchGitea(query),
|
|
]);
|
|
|
|
return results.flatMap(r => r.status === "fulfilled" ? r.value : []);
|
|
}
|
|
|
|
async function searchGitHub(query: string): Promise<RepoResult[]> {
|
|
const creds = await getRawCredentialsByProvider("github");
|
|
if (creds.length === 0) return [];
|
|
|
|
const results: RepoResult[] = [];
|
|
|
|
for (const cred of creds) {
|
|
try {
|
|
const res = await fetch(
|
|
`https://api.github.com/search/repositories?q=${encodeURIComponent(query)}&per_page=10&sort=updated`,
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${cred.token}`,
|
|
Accept: "application/vnd.github+json",
|
|
"X-GitHub-Api-Version": "2022-11-28",
|
|
},
|
|
}
|
|
);
|
|
|
|
if (!res.ok) continue;
|
|
|
|
const data = await res.json();
|
|
for (const repo of data.items || []) {
|
|
results.push({
|
|
provider: "github",
|
|
fullName: repo.full_name,
|
|
url: repo.html_url,
|
|
description: repo.description || "",
|
|
defaultBranch: repo.default_branch || "main",
|
|
private: repo.private,
|
|
});
|
|
}
|
|
} catch {
|
|
// skip failed credential
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
async function searchGitLab(query: string): Promise<RepoResult[]> {
|
|
const creds = await getRawCredentialsByProvider("gitlab");
|
|
if (creds.length === 0) return [];
|
|
|
|
const results: RepoResult[] = [];
|
|
|
|
for (const cred of creds) {
|
|
const baseUrl = cred.baseUrl || "https://gitlab.com";
|
|
try {
|
|
const res = await fetch(
|
|
`${baseUrl}/api/v4/projects?search=${encodeURIComponent(query)}&per_page=10&order_by=updated_at&membership=true`,
|
|
{
|
|
headers: {
|
|
"PRIVATE-TOKEN": cred.token,
|
|
},
|
|
}
|
|
);
|
|
|
|
if (!res.ok) continue;
|
|
|
|
const data = await res.json();
|
|
for (const project of data) {
|
|
results.push({
|
|
provider: "gitlab",
|
|
fullName: project.path_with_namespace,
|
|
url: project.web_url,
|
|
description: project.description || "",
|
|
defaultBranch: project.default_branch || "main",
|
|
private: project.visibility === "private",
|
|
});
|
|
}
|
|
} catch {
|
|
// skip failed credential
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
async function searchGitea(query: string): Promise<RepoResult[]> {
|
|
const creds = await getRawCredentialsByProvider("gitea");
|
|
if (creds.length === 0) return [];
|
|
|
|
const results: RepoResult[] = [];
|
|
|
|
for (const cred of creds) {
|
|
const baseUrl = cred.baseUrl || "https://gitea.coreworlds.io";
|
|
try {
|
|
const res = await fetch(
|
|
`${baseUrl}/api/v1/repos/search?q=${encodeURIComponent(query)}&limit=10&sort=updated`,
|
|
{
|
|
headers: {
|
|
Authorization: `token ${cred.token}`,
|
|
},
|
|
}
|
|
);
|
|
|
|
if (!res.ok) {
|
|
console.error(`[repo-search] Gitea search failed: ${res.status} ${res.statusText}`);
|
|
continue;
|
|
}
|
|
|
|
const data = await res.json();
|
|
// Rewrite internal service URLs to external Gitea URL
|
|
const externalUrl = process.env.GITEA_EXTERNAL_URL || "https://gitea.coreworlds.io";
|
|
for (const repo of data.data || []) {
|
|
let htmlUrl: string = repo.html_url || "";
|
|
if (baseUrl !== externalUrl && htmlUrl.startsWith(baseUrl)) {
|
|
htmlUrl = externalUrl + htmlUrl.slice(baseUrl.length);
|
|
}
|
|
results.push({
|
|
provider: "gitea",
|
|
fullName: repo.full_name,
|
|
url: htmlUrl,
|
|
description: repo.description || "",
|
|
defaultBranch: repo.default_branch || "main",
|
|
private: repo.private,
|
|
});
|
|
}
|
|
} catch (err) {
|
|
console.error(`[repo-search] Gitea search error:`, err);
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|