diff --git a/scripts/update-ghcr-downloads-badge.mjs b/scripts/update-ghcr-downloads-badge.mjs deleted file mode 100644 index edab7f2a..00000000 --- a/scripts/update-ghcr-downloads-badge.mjs +++ /dev/null @@ -1,107 +0,0 @@ -const DEFAULT_OUTPUT = ".github/badges/ghcr-downloads.json"; -const GH_API_BASE = "https://api.github.com"; - -const owner = process.env.GHCR_OWNER || process.env.GITHUB_REPOSITORY_OWNER; -const packageName = process.env.GHCR_PACKAGE || "charon"; -const outputPath = process.env.BADGE_OUTPUT || DEFAULT_OUTPUT; -const token = process.env.GITHUB_TOKEN || ""; - -if (!owner) { - throw new Error("GHCR owner is required. Set GHCR_OWNER or GITHUB_REPOSITORY_OWNER."); -} - -const headers = { - Accept: "application/vnd.github+json", -}; - -if (token) { - headers.Authorization = `Bearer ${token}`; -} - -const formatCount = (value) => { - if (value >= 1_000_000_000) { - return `${(value / 1_000_000_000).toFixed(1).replace(/\.0$/, "")}B`; - } - if (value >= 1_000_000) { - return `${(value / 1_000_000).toFixed(1).replace(/\.0$/, "")}M`; - } - if (value >= 1_000) { - return `${(value / 1_000).toFixed(1).replace(/\.0$/, "")}k`; - } - return String(value); -}; - -const getNextLink = (linkHeader) => { - if (!linkHeader) { - return null; - } - const match = linkHeader.match(/<([^>]+)>;\s*rel="next"/); - return match ? match[1] : null; -}; - -const fetchPage = async (url) => { - const response = await fetch(url, { headers }); - if (!response.ok) { - const detail = await response.text(); - const error = new Error(`Request failed: ${response.status} ${response.statusText}`); - error.status = response.status; - error.detail = detail; - throw error; - } - const data = await response.json(); - const link = response.headers.get("link"); - return { data, next: getNextLink(link) }; -}; - -const fetchAllVersions = async (baseUrl) => { - let url = `${baseUrl}?per_page=100`; - const versions = []; - - while (url) { - const { data, next } = await fetchPage(url); - versions.push(...data); - url = next; - } - - return versions; -}; - -const fetchVersionsWithFallback = async () => { - const userUrl = `${GH_API_BASE}/users/${owner}/packages/container/${packageName}/versions`; - try { - return await fetchAllVersions(userUrl); - } catch (error) { - if (error.status !== 404) { - throw error; - } - } - - const orgUrl = `${GH_API_BASE}/orgs/${owner}/packages/container/${packageName}/versions`; - return fetchAllVersions(orgUrl); -}; - -const run = async () => { - const versions = await fetchVersionsWithFallback(); - const totalDownloads = versions.reduce( - (sum, version) => sum + (version.download_count || 0), - 0 - ); - - const badge = { - schemaVersion: 1, - label: "GHCR pulls", - message: formatCount(totalDownloads), - color: "blue", - cacheSeconds: 3600, - }; - - const output = `${JSON.stringify(badge, null, 2)}\n`; - await import("node:fs/promises").then((fs) => fs.writeFile(outputPath, output)); - - console.log(`GHCR downloads: ${totalDownloads} -> ${outputPath}`); -}; - -run().catch((error) => { - console.error(error); - process.exit(1); -});