diff --git a/contributors.json b/contributors.json index 59057dfa33..86f480074c 100644 --- a/contributors.json +++ b/contributors.json @@ -1,5 +1,5 @@ { - "⚠️": "NOTE: this is an auto-generated list. Do not modify it.", + "ℹ️": "Use `npm run list-contributors`. as a reference to update this list.", "contributors": [ { "name": "eliandoran", @@ -17,37 +17,29 @@ "name": "adoriandoran", "url": "https://github.com/adoriandoran" }, - { - "name": "pano9000", - "url": "https://github.com/pano9000" - }, { "name": "perfectra1n", "url": "https://github.com/perfectra1n" }, { - "name": "JYC333", - "url": "https://github.com/JYC333" + "name": "pano9000", + "url": "https://github.com/pano9000" }, { "name": "SiriusXT", "url": "https://github.com/SiriusXT" }, { - "name": "tony", - "url": "https://github.com/tony" - }, - { - "name": "Nriver", - "url": "https://github.com/Nriver" + "name": "JYC333", + "url": "https://github.com/JYC333" }, { "name": "francistw", "url": "https://github.com/francistw" }, { - "name": "isaul32", - "url": "https://github.com/isaul32" + "name": "Nriver", + "url": "https://github.com/Nriver" }, { "name": "thfrei", diff --git a/package.json b/package.json index 91ef5a4c4d..17254a5179 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "dev:linter-fix": "cross-env NODE_OPTIONS=--max_old_space_size=4096 eslint . --fix", "postinstall": "tsx scripts/electron-rebuild.mts && pnpm prepare", "prepare": "pnpm run --filter pdfjs-viewer --filter share-theme build && pnpm run --filter web-clipper postinstall", - "update-contributor-list": "tsx ./scripts/update-contributor-list.ts" + "list-contributors": "tsx ./scripts/list-contributors.ts" }, "private": true, "devDependencies": { diff --git a/scripts/list-contributors.ts b/scripts/list-contributors.ts new file mode 100644 index 0000000000..02a7c534b7 --- /dev/null +++ b/scripts/list-contributors.ts @@ -0,0 +1,87 @@ +import { execSync} from "node:child_process"; + +interface ContributorInfo { + name: string; + fullName?: string + email?: string; + commitCount: number; + url: string; +} + +interface showTableParams { + title: string; + comment?: string; + contributors: ContributorInfo[]; + columns: (keyof ContributorInfo)[]; +} + +async function main() { + listLocalGitContributors(); + await listGitHubContributors(); +} + +async function listGitHubContributors() { + let list: any[] | null = null; + + const response = await fetch("https://api.github.com/repos/TriliumNext/Trilium/contributors"); + if (response.ok) { + list = await response.json(); + } else { + console.error(`Unable to request the contributor list from GitHub. Reason: ${response.statusText}`); + } + + if (!list) { + return; + } + + const contributors: ContributorInfo[] = list.map((c) => { + return { + name: c.login, + url: c.html_url, + commitCount: c.contributions + } as ContributorInfo; + }); + + showTable({ + title: "GitHub Contributor List", + comment: "Note: the GitHub list also include contributors that did not directly contribute to Trilium, but to submodules used in the Trilium's repo.", + contributors: contributors, + columns: ["name", "url", "commitCount"] + }); +} + +function listLocalGitContributors() { + const rawOutput = execSync("git shortlog -sne --no-merges HEAD -- src/ apps/") + .toString() + .split("\n") + .slice(0, 20); + + const contributors: ContributorInfo[] = rawOutput.map((line: string) => { + const match = line.match(/^\s*(\d+)\s+(.+?)\s+<(.+)>$/); + if (!match) { + return null; + } + return { + name: match[2], + email: match[3], + commitCount: parseInt(match[1]) + } + }); + + showTable({ + title: "Local Git Contributor List", + comment: "", + columns: ["name", "email", "commitCount"], + contributors: contributors.filter((c: ContributorInfo | null) => c !== null) + }); +} + +function showTable(params: showTableParams) { + console.log(`\n──── ${params.title} ────`); + if (params.comment) { + console.log(`\n${params.comment}\n`); + } + console.table(params.contributors, params.columns); +} + +main(); \ No newline at end of file diff --git a/scripts/update-contributor-list.ts b/scripts/update-contributor-list.ts deleted file mode 100644 index d6478c2da4..0000000000 --- a/scripts/update-contributor-list.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Contributor, ContributorList } from "../packages/commons/"; -import { writeFileSync } from "fs"; - -// Keep honorific contributors at top of the list, even if their commit count -// is exceeded by another users. -const PINNED_CONTRIBUTORS: Record> = { - "eliandoran": {fullName: "Elian Doran", role: "lead-dev"}, - "zadam": {fullName: "Zadam", role: "original-dev"} -}; - -// Bots marked as users on the GitHub profile info to exclude from the listing -const BOTS = [ - "weblate" -]; - -async function main() { - console.log("Retrieving the contributor list..."); - - let data: any = {}; - try { - data = await fetchContributors(); - } catch (ex) { - console.error(ex); - return; - } - - writeFileSync("contributors.json", JSON.stringify(data, null, 4)); - console.log("Done."); -} - -async function fetchContributors() { - const response = await fetch("https://api.github.com/repos/TriliumNext/Trilium/contributors"); - - if (response.ok) { - return { - "⚠️": "NOTE: this is an auto-generated list. Do not modify it.", - contributors: processContributorList(await response.json()) - } as ContributorList - } else { - throw new Error(`Unable to request the contributor list from GitHub. Reason: ${response.statusText}`); - } -} - -function processContributorList(contributorInfo: GithubContributor[]) { - return contributorInfo - // Filter out bots - .filter((c) => c.type === "User" && !BOTS.includes(c.login)) - // Sort by the commit count. Honorific contributors are always first. - .sort(contributorOrderer) - .map((c) => { - let pinnedInfo = PINNED_CONTRIBUTORS[c.login]; - - return { - name: c.login, - fullName: pinnedInfo?.fullName, - url: c.html_url, - role: pinnedInfo?.role - } as Contributor; - }); -} - -function contributorOrderer(a, b) { - const isAPinned = (a.login in PINNED_CONTRIBUTORS); - const isBPinned = (b.login in PINNED_CONTRIBUTORS); - - // Pinned contributors come first - if (isAPinned !== isBPinned) { - return isAPinned ? -1 : 1; - } - - // Within each group, sort by contributions - return b.contributions - a.contributions; -} - -main(); \ No newline at end of file