Files
hanzo.ai/scripts/forge-mirrors.mjs
Cursor Agentandz 74a1a48c54 oss: every Hanzo org, tracked forks, and the year's contributions
The census now asks for every Hanzo organization this GitHub account belongs to, and it counts an organization's forks, because a tracked fork is a project whose main we follow. zeekay and zooqueen are read from GitHub's own contribution count for the past year. scripts/forge-mirrors.mjs prints the organizations forge.hanzo.ai does not have yet and, with FORGE_TOKEN, pull-mirrors the public repositories with GitHub kept as the source.

Co-authored-by: z <[email protected]>
2026-10-27 05:10:33 +00:00

105 lines
3.8 KiB
JavaScript

/**
* GitHub is canonical. forge.hanzo.ai is where those repositories are browsed
* and where issues are kept. This compares the accounts the census asks for
* (lib/data/oss.json `asked`) with the organizations the forge already has.
*
* Without FORGE_TOKEN it prints the gap and exits 0. A marketing build must
* not need a forge credential.
*
* With FORGE_TOKEN and --apply it creates a missing organization and pulls
* each of its public GitHub repositories across as a mirror (GitHub stays the
* source; the forge copy follows it). Issues, pull requests, labels,
* milestones, releases and the wiki come with the mirror.
*
* FORGE_TOKEN=… node scripts/forge-mirrors.mjs --apply
*/
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const FORGE = "https://forge.hanzo.ai/v1";
const token = process.env.FORGE_TOKEN;
const apply = process.argv.includes("--apply");
const here = dirname(fileURLToPath(import.meta.url));
const census = JSON.parse(readFileSync(join(here, "..", "lib", "data", "oss.json"), "utf8"));
const asked = census.asked ?? census.orgs.map((o) => o.name);
async function forgeOrgs() {
const names = [];
for (let page = 1; ; page++) {
const res = await fetch(`${FORGE}/orgs?limit=50&page=${page}`);
if (!res.ok) throw new Error(`forge orgs ${res.status}`);
const rows = await res.json();
if (!Array.isArray(rows) || !rows.length) break;
names.push(...rows.map((o) => o.username));
if (rows.length < 50) break;
}
return new Set(names);
}
async function forgeRepoCount(org) {
let n = 0;
for (let page = 1; ; page++) {
const res = await fetch(`${FORGE}/orgs/${org}/repos?limit=50&page=${page}`);
if (!res.ok) return null;
const rows = await res.json();
if (!Array.isArray(rows) || !rows.length) break;
n += rows.length;
if (rows.length < 50) break;
}
return n;
}
const have = await forgeOrgs();
const missing = asked.filter((name) => name !== "zeekay" && !have.has(name));
console.log(`forge has ${have.size} organizations; ${missing.length} Hanzo organizations are not there`);
if (missing.length) console.log(missing.join("\n"));
for (const org of asked.filter((name) => have.has(name))) {
const onForge = await forgeRepoCount(org);
const onGitHub = census.orgs.find((o) => o.name === org)?.repos ?? 0;
if (onForge !== onGitHub) console.log(`${org}: forge ${onForge ?? "unread"} repositories, GitHub ${onGitHub}`);
}
if (!apply) {
console.log("dry run. FORGE_TOKEN and --apply create the missing organizations and pull-mirror their public GitHub repositories.");
process.exit(0);
}
if (!token) {
console.error("FORGE_TOKEN is not set");
process.exit(1);
}
const headers = { authorization: `token ${token}`, "content-type": "application/json", accept: "application/json" };
for (const org of missing) {
if (org === "zeekay") continue;
const res = await fetch(`${FORGE}/orgs`, { method: "POST", headers, body: JSON.stringify({ username: org, visibility: "public" }) });
console.log(`create ${org}: ${res.status}`);
}
const github = census.public.filter((full) => asked.some((org) => full.startsWith(`${org}/`)));
for (const full of github) {
const [owner, repo] = full.split("/");
const there = await fetch(`${FORGE}/repos/${owner}/${repo}`, { headers });
if (there.ok) continue;
const res = await fetch(`${FORGE}/repos/migrate`, {
method: "POST",
headers,
body: JSON.stringify({
clone_addr: `https://github.com/${full}`,
repo_owner: owner,
repo_name: repo,
service: "github",
mirror: true,
mirror_interval: "8h",
issues: true,
pull_requests: true,
labels: true,
milestones: true,
releases: true,
wiki: true,
}),
});
console.log(`mirror ${full}: ${res.status}`);
}