diff --git a/bin/readme b/bin/readme new file mode 100644 index 0000000..25bc3e6 --- /dev/null +++ b/bin/readme @@ -0,0 +1,160 @@ +#!/usr/bin/env node + +import { readFileSync, writeFileSync } from "node:fs"; + +const token = process.env.GH_TOKEN; +const org = "umts"; +const stacks = { + rails: "rails-CC0000?logo=ruby-on-rails", + sinatra: "sinatra-000000?logo=ruby-sinatra", + react: "react-61DAFB?logo=react&logoColor=black", +}; + +async function fetchRepos() { + const query = ` + query($org: String!, $cursor: String) { + organization(login: $org) { + repositories(first: 100, after: $cursor, isArchived: false) { + pageInfo { + hasNextPage + endCursor + } + nodes { + name + visibility + homepageUrl + defaultBranchRef { + name + } + repositoryTopics(first: 100) { + nodes { + topic { name } + } + } + repositoryCustomPropertyValues(first: 100) { + nodes { + propertyName + value + } + } + } + } + } + } + `; + const repos = []; + let cursor = null; + while (true) { + const res = await fetch("https://api.github.com/graphql", { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ query, variables: { org, cursor } }), + }); + const json = await res.json(); + if (json.errors || !json.data) { + console.error(JSON.stringify(json, null, 2)); + process.exit(1); + } + const { nodes, pageInfo } = json.data.organization.repositories; + repos.push(...nodes); + if (!pageInfo.hasNextPage) break; + cursor = pageInfo.endCursor; + } + return repos + .filter((r) => + r.repositoryCustomPropertyValues.nodes.some( + (p) => p.propertyName === "dashboard" && p.value.includes("true"), + ), + ) + .sort((r1, r2) => { + const s1 = repoStackOrder(r1); + const s2 = repoStackOrder(r2); + return s1 !== s2 ? s1 - s2 : r1.name.localeCompare(r2.name); + }); +} + +function repoStackOrder(repo) { + const topics = repo.repositoryTopics.nodes.map((n) => n.topic.name); + const stackKeys = Object.keys(stacks); + const idx = stackKeys.findIndex((k) => topics.includes(k)); + return idx === -1 ? stackKeys.length : idx; +} + +function renderDashboard(repos) { + const apps = repos.filter((r) => r.homepageUrl); + const appRows = apps + .map( + (repo) => `
| Applications | +||
|---|---|---|
| Libraries, Tools & Infrastructure | +