mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-15 23:24:52 +09:00
Merge pull request #1037 from bbassie/feature/changelog-stats
Add contributors title and statistics to the changelog script
This commit is contained in:
2 files changed
+73
-5
No files matched your search
+17
-2
@@ -11,8 +11,8 @@ export async function githubFetch(
|
||||
init = {
|
||||
...init,
|
||||
headers: {
|
||||
...init.headers as Record<string, string> ?? {},
|
||||
"Accept": "application/vnd.github+json",
|
||||
...init.headers as Record<string, string> ?? {},
|
||||
}
|
||||
};
|
||||
if (process.env.GH_TOKEN) {
|
||||
@@ -24,7 +24,9 @@ export async function githubFetch(
|
||||
console.log(response.headers);
|
||||
throw new Error(`GitHub replied with ${response.status} ${response.statusText}: ${await response.text()}`);
|
||||
}
|
||||
if (!response.headers.get("Content-Type")?.startsWith("application/json")) {
|
||||
const accept = init.headers!["Accept"];
|
||||
const contentType = accept === "application/vnd.github+json" ? "application/json" : accept;
|
||||
if (!response.headers.get("Content-Type")?.startsWith(contentType)) {
|
||||
throw new Error(
|
||||
`GitHub replied with ${response.status} ${response.statusText}: ${response.headers.get("Content-Type")}`
|
||||
);
|
||||
@@ -41,6 +43,15 @@ export async function githubFetchJson<T>(
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
export async function githubFetchText(
|
||||
path: string,
|
||||
query: Record<string, string> = {},
|
||||
init: RequestInit & { headers?: Record<string, string> } = {},
|
||||
): Promise<string> {
|
||||
const response = await githubFetch(path, query, init);
|
||||
return await response.text();
|
||||
}
|
||||
|
||||
export async function githubFetchJsonPaginated<T>(
|
||||
path: string,
|
||||
query: Record<string, string> = {},
|
||||
@@ -117,6 +128,10 @@ export interface Release {
|
||||
updated_at?: string | null,
|
||||
}
|
||||
|
||||
export interface Comparison {
|
||||
total_commits: number,
|
||||
}
|
||||
|
||||
export interface Commit {
|
||||
sha: string,
|
||||
commit: {
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
import {
|
||||
type Comparison,
|
||||
type Release,
|
||||
type Issue,
|
||||
githubFetchJson,
|
||||
githubFetchJsonPaginated,
|
||||
githubFetchText,
|
||||
} from "./github_api.mts";
|
||||
|
||||
type Changelog = Record<string, string[]>;
|
||||
|
||||
type Statistics = {
|
||||
commits: number,
|
||||
pullRequests: number,
|
||||
filesChanged: number,
|
||||
lineAdditions: number,
|
||||
lineDeletions: number,
|
||||
};
|
||||
|
||||
const repository = "clusterio/clusterio";
|
||||
const branch = "master";
|
||||
|
||||
@@ -187,10 +197,41 @@ async function fetchIssuesUpdatedSince(since: string) {
|
||||
);
|
||||
}
|
||||
|
||||
async function fetchStatistics(lastRelease: Release, pullRequests: Issue[]): Promise<Statistics> {
|
||||
const path = `/repos/${repository}/compare/${lastRelease.tag_name}...${branch}`;
|
||||
const comparison = await githubFetchJson<Comparison>(path, { per_page: "1" });
|
||||
// The JSON response lists at most 300 files, the diff has all of them.
|
||||
const diff = await githubFetchText(path, {}, { headers: { "Accept": "application/vnd.github.diff" } });
|
||||
let filesChanged = 0;
|
||||
let lineAdditions = 0;
|
||||
let lineDeletions = 0;
|
||||
let inHunk = false; // Skips the ---/+++ file headers
|
||||
for (const line of diff.split("\n")) {
|
||||
if (line.startsWith("diff --git ")) {
|
||||
filesChanged += 1;
|
||||
inHunk = false;
|
||||
} else if (line.startsWith("@@")) {
|
||||
inHunk = true;
|
||||
} else if (inHunk && line.startsWith("+")) {
|
||||
lineAdditions += 1;
|
||||
} else if (inHunk && line.startsWith("-")) {
|
||||
lineDeletions += 1;
|
||||
}
|
||||
}
|
||||
return {
|
||||
commits: comparison.total_commits,
|
||||
pullRequests: pullRequests.length,
|
||||
filesChanged,
|
||||
lineAdditions,
|
||||
lineDeletions,
|
||||
};
|
||||
}
|
||||
|
||||
function printMarkdown(
|
||||
changelog: Changelog,
|
||||
issues: Issue[],
|
||||
users: Issue["user"][],
|
||||
statistics: Statistics,
|
||||
refText: (issue: Issue) => string,
|
||||
userText: (user: Issue["user"]) => string,
|
||||
) {
|
||||
@@ -216,8 +257,19 @@ function printMarkdown(
|
||||
}
|
||||
}
|
||||
|
||||
console.log("### Contributors\n");
|
||||
console.log(`Many thanks to the following for contributing to this release:`);
|
||||
console.log(users.map(userText).join("\n"))
|
||||
console.log(users.map(userText).join(", "));
|
||||
|
||||
const format = (value: number) => value.toLocaleString("en-US");
|
||||
console.log("\n### Statistics\n");
|
||||
console.log([
|
||||
`Commits: ${format(statistics.commits)}`,
|
||||
`Pull Requests: ${format(statistics.pullRequests)}`,
|
||||
`Files Changed: ${format(statistics.filesChanged)}`,
|
||||
`Additions: +${format(statistics.lineAdditions)}`,
|
||||
`Deletions: -${format(statistics.lineDeletions)}`,
|
||||
].join(" "));
|
||||
}
|
||||
|
||||
async function main() {
|
||||
@@ -232,17 +284,18 @@ async function main() {
|
||||
|
||||
const changelog = changelogFromPullRequests(pullRequests, issues);
|
||||
const users = [...new Map(pullRequests.map(issue => [issue.user.login, issue.user])).values()]
|
||||
const statistics = await fetchStatistics(lastRelease, pullRequests);
|
||||
|
||||
console.log();
|
||||
console.log("=== Github Release Markdown ===");
|
||||
printMarkdown(changelog, issues, users,
|
||||
printMarkdown(changelog, issues, users, statistics,
|
||||
issue => `${repository}#${issue.number}`,
|
||||
user => `@${user.login}`,
|
||||
);
|
||||
|
||||
console.log();
|
||||
console.log("=== Discord / Changelog Markdown ===");
|
||||
printMarkdown(changelog, issues, users,
|
||||
printMarkdown(changelog, issues, users, statistics,
|
||||
issue => `[#${issue.number}](<${issue.html_url}>)`,
|
||||
user => `[@${user.login}](<${user.html_url}>)`
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user