Skip to content

Commit f374942

Browse files
authored
更新 fetch-gh-data.ts
1 parent 3a9011a commit f374942

1 file changed

Lines changed: 150 additions & 141 deletions

File tree

scripts/fetch-gh-data.ts

Lines changed: 150 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,31 @@ import { config } from "dotenv";
1010
config();
1111

1212
const OUTPUT_FILE = join(
13-
dirname(fileURLToPath(import.meta.url)),
14-
"..",
15-
"src",
16-
"ghdata.json",
13+
dirname(fileURLToPath(import.meta.url)),
14+
"..",
15+
"src",
16+
"ghdata.json",
1717
);
1818
const REPO = { owner: "LanRhyme", name: "MicYou" };
1919
const EXCLUDE_USERS = new Set([
20-
"LanRhyme",
21-
"ChinsaaWei",
22-
"dependabot[bot]",
23-
"crowdin-bot",
20+
"LanRhyme",
21+
"ChinsaaWei",
22+
"dependabot[bot]",
23+
"crowdin-bot",
2424
]);
2525

2626
interface OutputData {
27-
version: string;
28-
releaseUrl: string;
29-
releaseDate: string;
30-
releaseNotes: string;
31-
contributors: Array<{
32-
login: string;
33-
avatar_url: string;
34-
html_url: string;
35-
contributions: number;
36-
}>;
37-
fetchedAt: string;
27+
version: string;
28+
releaseUrl: string;
29+
releaseDate: string;
30+
releaseNotes: string;
31+
contributors: Array<{
32+
login: string;
33+
avatar_url: string;
34+
html_url: string;
35+
contributions: number;
36+
}>;
37+
fetchedAt: string;
3838
}
3939

4040
// 合并的 GraphQL 查询
@@ -64,134 +64,143 @@ const QUERY = `
6464
`;
6565

6666
async function fetchGraphQL(
67-
query: string,
68-
variables: Record<string, string | null>,
69-
token: string,
67+
query: string,
68+
variables: Record<string, string | null>,
69+
token: string,
7070
) {
71-
const res = await fetch("https://api.github.com/graphql", {
72-
method: "POST",
73-
headers: {
74-
"Content-Type": "application/json",
75-
Authorization: `Bearer ${token}`,
76-
},
77-
body: JSON.stringify({ query, variables }),
78-
});
79-
if (!res.ok) throw new Error(`GitHub API error: ${res.status}`);
80-
return res.json();
71+
const res = await fetch("https://api.github.com/graphql", {
72+
method: "POST",
73+
headers: {
74+
"Content-Type": "application/json",
75+
Authorization: `Bearer ${token}`,
76+
},
77+
body: JSON.stringify({ query, variables }),
78+
});
79+
if (!res.ok) throw new Error(`GitHub API error: ${res.status}`);
80+
return res.json();
8181
}
8282

8383
async function main() {
84-
// 支持 GH_TOKEN 或 GITHUB_TOKEN(GitHub Actions 默认提供)
85-
const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
86-
if (!token) {
87-
console.error("Error: Set GH_TOKEN or GITHUB_TOKEN environment variable.");
88-
process.exit(1);
89-
}
90-
91-
console.log("Fetching GitHub data...");
92-
93-
try {
94-
// 获取 release
95-
const releaseRes = await fetchGraphQL(
96-
`query($owner: String!, $name: String!) {
84+
// 支持 GH_TOKEN 或 GITHUB_TOKEN(GitHub Actions 默认提供)
85+
const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
86+
if (!token) {
87+
console.error("Error: Set GH_TOKEN or GITHUB_TOKEN environment variable.");
88+
process.exit(1);
89+
}
90+
91+
console.log("Fetching GitHub data...");
92+
93+
try {
94+
// 获取 release
95+
const releaseRes = await fetchGraphQL(
96+
`query($owner: String!, $name: String!) {
9797
repository(owner: $owner, name: $name) {
98-
latestRelease { tagName publishedAt url description }
98+
releases(first: 20, orderBy: {field: CREATED_AT, direction: DESC}) {
99+
nodes {
100+
tagName
101+
publishedAt
102+
url
103+
description
104+
isPrerelease
105+
}
106+
}
99107
}
100108
}`,
101-
REPO,
102-
token,
103-
);
104-
const release = releaseRes.data?.repository?.latestRelease;
105-
if (!release) throw new Error("No releases found");
106-
107-
// 分页获取所有 commits
108-
const commits: Array<{
109-
author?: {
110-
user?: { login: string; avatarUrl: string; url: string } | null;
111-
} | null;
112-
}> = [];
113-
let after: string | null = null;
114-
let page = 0;
115-
116-
while (true) {
117-
page++;
118-
const res = await fetchGraphQL(QUERY, { ...REPO, after }, token);
119-
const history = res.data?.repository?.defaultBranchRef?.target?.history;
120-
if (!history) break;
121-
commits.push(...history.nodes);
122-
console.log(` Page ${page}: ${commits.length} commits`);
123-
if (!history.pageInfo.hasNextPage) break;
124-
after = history.pageInfo.endCursor;
125-
}
126-
127-
// 统计贡献者
128-
const contributorMap = new Map<
129-
string,
130-
{
131-
login: string;
132-
avatar_url: string;
133-
html_url: string;
134-
contributions: number;
135-
}
136-
>();
137-
for (const c of commits) {
138-
const u = c.author?.user;
139-
if (!u?.login || EXCLUDE_USERS.has(u.login) || u.login.includes("[bot]"))
140-
continue;
141-
const existing = contributorMap.get(u.login);
142-
if (existing) existing.contributions++;
143-
else
144-
contributorMap.set(u.login, {
145-
login: u.login,
146-
avatar_url: u.avatarUrl,
147-
html_url: u.url,
148-
contributions: 1,
149-
});
150-
}
151-
const contributors = Array.from(contributorMap.values()).sort(
152-
(a, b) => b.contributions - a.contributions,
153-
);
154-
155-
const newData = {
156-
version: release.tagName.replace(/^v/, ""),
157-
releaseUrl: release.url,
158-
releaseDate: release.publishedAt,
159-
releaseNotes: release.description || "",
160-
contributors,
161-
};
162-
163-
// 检查是否有变化
164-
if (existsSync(OUTPUT_FILE)) {
165-
const existing: OutputData = JSON.parse(
166-
readFileSync(OUTPUT_FILE, "utf-8"),
167-
);
168-
if (
169-
existing.version === newData.version &&
170-
JSON.stringify(existing.contributors) ===
171-
JSON.stringify(newData.contributors)
172-
) {
173-
console.log(
174-
`✓ Version: ${newData.version}, Contributors: ${newData.contributors.length} (no changes)`,
175-
);
176-
return;
177-
}
178-
}
179-
180-
writeFileSync(
181-
OUTPUT_FILE,
182-
JSON.stringify(
183-
{ ...newData, fetchedAt: new Date().toISOString() },
184-
null,
185-
2,
186-
),
187-
);
188-
console.log(
189-
`✓ Version: ${newData.version}, Contributors: ${newData.contributors.length}`,
190-
);
191-
} catch (error) {
192-
console.error("Failed:", error);
193-
process.exit(1);
194-
}
109+
REPO,
110+
token,
111+
);
112+
const releases = releaseRes.data?.repository?.releases?.nodes || [];
113+
const release = releases.find((r: any) => r && !r.isPrerelease);
114+
if (!release) throw new Error("No stable release found");
115+
116+
// 分页获取所有 commits
117+
const commits: Array<{
118+
author?: {
119+
user?: { login: string; avatarUrl: string; url: string } | null;
120+
} | null;
121+
}> = [];
122+
let after: string | null = null;
123+
let page = 0;
124+
125+
while (true) {
126+
page++;
127+
const res = await fetchGraphQL(QUERY, { ...REPO, after }, token);
128+
const history = res.data?.repository?.defaultBranchRef?.target?.history;
129+
if (!history) break;
130+
commits.push(...history.nodes);
131+
console.log(` Page ${page}: ${commits.length} commits`);
132+
if (!history.pageInfo.hasNextPage) break;
133+
after = history.pageInfo.endCursor;
134+
}
135+
136+
// 统计贡献者
137+
const contributorMap = new Map<
138+
string,
139+
{
140+
login: string;
141+
avatar_url: string;
142+
html_url: string;
143+
contributions: number;
144+
}
145+
>();
146+
for (const c of commits) {
147+
const u = c.author?.user;
148+
if (!u?.login || EXCLUDE_USERS.has(u.login) || u.login.includes("[bot]"))
149+
continue;
150+
const existing = contributorMap.get(u.login);
151+
if (existing) existing.contributions++;
152+
else
153+
contributorMap.set(u.login, {
154+
login: u.login,
155+
avatar_url: u.avatarUrl,
156+
html_url: u.url,
157+
contributions: 1,
158+
});
159+
}
160+
const contributors = Array.from(contributorMap.values()).sort(
161+
(a, b) => b.contributions - a.contributions,
162+
);
163+
164+
const newData = {
165+
version: release.tagName.replace(/^v/, ""),
166+
releaseUrl: release.url,
167+
releaseDate: release.publishedAt,
168+
releaseNotes: release.description || "",
169+
contributors,
170+
};
171+
172+
// 检查是否有变化
173+
if (existsSync(OUTPUT_FILE)) {
174+
const existing: OutputData = JSON.parse(
175+
readFileSync(OUTPUT_FILE, "utf-8"),
176+
);
177+
if (
178+
existing.version === newData.version &&
179+
JSON.stringify(existing.contributors) ===
180+
JSON.stringify(newData.contributors)
181+
) {
182+
console.log(
183+
`✓ Version: ${newData.version}, Contributors: ${newData.contributors.length} (no changes)`,
184+
);
185+
return;
186+
}
187+
}
188+
189+
writeFileSync(
190+
OUTPUT_FILE,
191+
JSON.stringify(
192+
{ ...newData, fetchedAt: new Date().toISOString() },
193+
null,
194+
2,
195+
),
196+
);
197+
console.log(
198+
`✓ Version: ${newData.version}, Contributors: ${newData.contributors.length}`,
199+
);
200+
} catch (error) {
201+
console.error("Failed:", error);
202+
process.exit(1);
203+
}
195204
}
196205

197-
main();
206+
main();

0 commit comments

Comments
 (0)