Files
blackroad-os-archive/scripts/scan_github_repos.ts
2025-11-24 04:54:49 -06:00

118 lines
2.9 KiB
TypeScript

import yaml from "js-yaml";
type RepoRecord = {
id: string;
full_name: string;
org: string;
description: string;
visibility: "public" | "private";
status: "active" | "archived" | "experimental" | "legacy";
primary_domain: string | null;
home_pack: string;
created_at: string;
updated_at: string;
tags: string[];
owner_handles: string[];
};
type GitHubRepo = {
name: string;
full_name: string;
private: boolean;
description: string | null;
created_at: string;
updated_at: string;
};
const TOKEN = process.env.GITHUB_TOKEN;
const ORGS = process.env.GITHUB_ORGS?.split(",").map((org) => org.trim()).filter(Boolean) ?? [];
async function githubFetch(url: string) {
const headers: Record<string, string> = {
Accept: "application/vnd.github+json",
"User-Agent": "blackroad-os-archive"
};
if (TOKEN) {
headers.Authorization = `Bearer ${TOKEN}`;
}
const response = await fetch(url, { headers });
if (!response.ok) {
throw new Error(`GitHub request failed: ${response.status} ${response.statusText} for ${url}`);
}
return response.json();
}
async function fetchReposForOrg(org: string): Promise<RepoRecord[]> {
const repos: RepoRecord[] = [];
let page = 1;
while (true) {
const url = `https://api.github.com/orgs/${org}/repos?per_page=100&page=${page}`;
const data: GitHubRepo[] = await githubFetch(url);
if (!data.length) break;
data.forEach((repo) => {
let id: string;
if (repo.name.startsWith("blackroad-os-")) {
id = repo.name.replace(/^blackroad-os-/, "");
} else {
id = `other-${repo.name}`;
console.warn(
`Repository '${repo.full_name}' does not start with 'blackroad-os-'. Assigned id: '${id}'.`
);
}
repos.push({
id,
full_name: repo.full_name,
org,
description: repo.description ?? "",
visibility: repo.private ? "private" : "public",
status: "active",
primary_domain: null,
home_pack: "tbd",
created_at: repo.created_at,
updated_at: repo.updated_at,
tags: [],
owner_handles: []
});
});
if (data.length < 100) break;
page += 1;
}
return repos;
}
export async function scanGithubRepos(): Promise<RepoRecord[]> {
if (!ORGS.length) {
throw new Error("GITHUB_ORGS env var is required (comma-separated list).");
}
const results: RepoRecord[] = [];
for (const org of ORGS) {
const repos = await fetchReposForOrg(org);
results.push(...repos);
}
return results;
}
async function main() {
try {
const repos = await scanGithubRepos();
const payload = { repos };
const yamlOutput = yaml.dump(payload, { lineWidth: 120 });
process.stdout.write(`# Generated by scan_github_repos.ts\n`);
process.stdout.write(yamlOutput);
} catch (error) {
console.error((error as Error).message);
process.exit(1);
}
}
if (require.main === module) {
main();
}