Files
homelab/apps/harness/src/lib/repo-search.ts
Julia McGhee ce58800b36
Some checks failed
CI / lint-and-test (push) Successful in 39s
Deploy Production / deploy (push) Failing after 51s
CI / build (push) Failing after 46s
Fix Gitea repo search: correct service name and add UI support
- 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
2026-03-21 22:15:18 +00:00

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;
}