mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
Add script which uses GitHub's REST API to fetch issues and pull requests that have changed since the last release, parse out the changelog entries from merged pull requests, and print a formatted version of the changelog suitable for copying into the release description, the CHANGELOG.md file and the Discord announcement. The script expects Pull Requests to have a `### Changelog` section in them with a code block containing changelog entries. As an added bonus the script can parse out `#<number>` references so that you do not need to write it out in the ugly `[#id](long-url-with-id-repeated)` format. Updates documentation and pull request template to describe the changelog format and usage of the formatting script. Includes improvements from review and a second look.
137 lines
3.2 KiB
TypeScript
137 lines
3.2 KiB
TypeScript
export async function githubFetch(
|
|
path: string,
|
|
query: Record<string, string>= {},
|
|
init: RequestInit & { headers?: Record<string, string> } = {},
|
|
) {
|
|
const url = new URL("https://api.github.com/");
|
|
url.pathname = path;
|
|
for (const [name, value] of Object.entries(query)) {
|
|
url.searchParams.set(name, value);
|
|
}
|
|
init = {
|
|
...init,
|
|
headers: {
|
|
...init.headers as Record<string, string> ?? {},
|
|
"Accept": "application/vnd.github+json",
|
|
}
|
|
};
|
|
if (process.env.GH_TOKEN) {
|
|
init.headers!["Authorization"] = `Bearer ${process.env.GH_TOKEN}`;
|
|
}
|
|
console.log("Fetching", url.href);
|
|
const response = await fetch(url, init);
|
|
if (!response.ok) {
|
|
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")) {
|
|
throw new Error(
|
|
`GitHub replied with ${response.status} ${response.statusText}: ${response.headers.get("Content-Type")}`
|
|
);
|
|
}
|
|
return response;
|
|
}
|
|
|
|
export async function githubFetchJson<T>(
|
|
path: string,
|
|
query: Record<string, string> = {},
|
|
init: RequestInit & { headers?: Record<string, string> } = {},
|
|
): Promise<T> {
|
|
const response = await githubFetch(path, query, init);
|
|
return await response.json();
|
|
}
|
|
|
|
export async function githubFetchJsonPaginated<T>(
|
|
path: string,
|
|
query: Record<string, string> = {},
|
|
init: RequestInit & { headers?: Record<string, string> } = {},
|
|
shouldContinue: (result: T[]) => boolean = () => true,
|
|
): Promise<T[]> {
|
|
const data: T[] = [];
|
|
let pagesRemaining = true;
|
|
query = {
|
|
...query,
|
|
per_page: "100",
|
|
};
|
|
while (pagesRemaining) {
|
|
const response = await githubFetch(path, query, init);
|
|
const responseItems = await response.json();
|
|
data.push(...responseItems);
|
|
const linkHeader = response.headers.get("Link");
|
|
pagesRemaining = linkHeader?.includes(`rel="next"`) ?? false;
|
|
if (pagesRemaining) {
|
|
pagesRemaining = shouldContinue(responseItems);
|
|
}
|
|
if (pagesRemaining) {
|
|
query = {
|
|
...query,
|
|
page: String((query.page ? (Number(query.page)) : 1) + 1),
|
|
}
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
// Minimal types that include only what is used and useful for our scripts. See
|
|
// https://docs.github.com/en/rest for complete reference.
|
|
export interface PullRequest {
|
|
number: number,
|
|
url: string,
|
|
html_url: string,
|
|
state: string,
|
|
title: string,
|
|
body: string | null,
|
|
created_at: string,
|
|
updated_at: string,
|
|
closed_at: string | null,
|
|
merged_at: string | null,
|
|
merge_commit_sha: string | null,
|
|
}
|
|
|
|
export interface Issue {
|
|
number: number,
|
|
title: string,
|
|
url: string,
|
|
html_url: string,
|
|
state: string,
|
|
body?: string | null,
|
|
pull_request?: {
|
|
url: string,
|
|
html_url: string,
|
|
merged_at?: string | null,
|
|
},
|
|
}
|
|
|
|
export interface Release {
|
|
tag_name: string,
|
|
target_commitish: string,
|
|
name: string | null,
|
|
body: string | null,
|
|
created_at: string,
|
|
published_at: string | null,
|
|
updated_at?: string | null,
|
|
}
|
|
|
|
export interface Commit {
|
|
sha: string,
|
|
commit: {
|
|
message: string,
|
|
},
|
|
author: null | {} | {
|
|
name?: null | string,
|
|
login: string,
|
|
type: string,
|
|
},
|
|
parents: {
|
|
sha: string,
|
|
}[],
|
|
}
|
|
|
|
export interface Reference {
|
|
ref: string,
|
|
object: {
|
|
type: string,
|
|
sha: string,
|
|
},
|
|
}
|