contributor list: switch to manual update, add a tool for a reference list (local Git + GitHub listing)

This commit is contained in:
Adorian Doran
2026-04-19 11:10:45 +03:00
parent 4e55b29041
commit 900f308349
4 changed files with 95 additions and 91 deletions

View File

@@ -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",

View File

@@ -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": {

View File

@@ -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();

View File

@@ -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<string, Pick<Contributor, "fullName" | "role">> = {
"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();