fix declarations

This commit is contained in:
Saksham
2025-11-23 19:01:57 +05:30
parent 6242c6ca8b
commit 84be28708e

View File

@@ -10,69 +10,67 @@ const EVENT_PATH = process.env.GITHUB_EVENT_PATH!;
const bot = new Bot(BOT_TOKEN); const bot = new Bot(BOT_TOKEN);
const FileSchema = z.object({ const FileNode = z.object({ path: z.string() });
path: z.string(),
});
const PullRequestSchema = z.object({ const PullRequestSchema = z.object({
action: z.string(), action: z.string(),
number: z.number(), number: z.number(),
repository: z.object({ repository: z.object({
full_name: z.string(), full_name: z.string(),
html_url: z.url() html_url: z.url(),
}), }),
pull_request: z.object({ pull_request: z.object({
url: z.url(), html_url: z.url().optional(),
url: z.url().optional(),
title: z.string(), title: z.string(),
body: z.string().nullable(), body: z.string().nullable(),
user: z.object({ user: z.object({ login: z.string(), html_url: z.url() }),
login: z.string(),
html_url: z.url()
}),
head: z.object({ ref: z.string() }), head: z.object({ ref: z.string() }),
base: z.object({ ref: z.string() }), base: z.object({ ref: z.string() }),
changed_files: z.number(), changed_files: z.number().optional().default(0),
additions: z.number(), additions: z.number().optional().default(0),
deletions: z.number() deletions: z.number().optional().default(0),
}) }),
}); });
const PushSchema = z.object({ const PushSchema = z.object({
ref: z.string(), ref: z.string(),
repository: z.object({ repository: z.object({
full_name: z.string(), full_name: z.string(),
html_url: z.url() html_url: z.url(),
}), }),
head_commit: z.object({ head_commit: z
id: z.string(), .object({
url: z.url(), id: z.string(),
message: z.string(), url: z.url(),
author: z.object({ message: z.string(),
name: z.string(), author: z.object({ name: z.string(), email: z.email() }),
email: z.email() added: z.array(z.string()).optional().default([]),
}), modified: z.array(z.string()).optional().default([]),
added: z.array(z.string()), removed: z.array(z.string()).optional().default([]),
modified: z.array(z.string()), })
removed: z.array(z.string()) .nullable(),
}).nullable()
}); });
function detectLanguage(files: string[]): string { function detectLanguage(files: string[]): string {
const ext = files.map(f => f.split(".").pop()?.toLowerCase() || ""); const ext = files.map((f) => (f.split(".").pop() || "").toLowerCase());
if (ext.includes("kt") || ext.includes("kts")) return "Kotlin"; if (ext.some((e) => e === "kt" || e === "kts")) return "Kotlin";
if (ext.includes("c") && !ext.includes("h")) return "C"; if (ext.some((e) => e === "rs")) return "Rust";
if (ext.includes("rs")) return "Rust"; if (ext.some((e) => e === "c")) return "C";
if (ext.includes("sh")) return "Shell"; if (ext.some((e) => e === "sh")) return "Shell";
if (ext.includes("ts") || ext.includes("tsx")) return "TypeScript"; if (ext.some((e) => e === "ts" || e === "tsx")) return "TypeScript";
return "Unknown"; return "Other";
} }
async function fetchPrFiles(repoFullName: string, prNumber: number): Promise<string[]> { async function fetchPrFiles(
repoFullName: string,
prNumber: number,
): Promise<string[]> {
const query = ` const query = `
query($owner: String!, $name: String!, $number: Int!) { query($owner:String!, $name:String!, $number:Int!) {
repository(owner: $owner, name: $name) { repository(owner:$owner, name:$name) {
pullRequest(number: $number) { pullRequest(number:$number) {
files(first: 100) { files(first:100) {
nodes { nodes {
path path
} }
@@ -84,74 +82,116 @@ async function fetchPrFiles(repoFullName: string, prNumber: number): Promise<str
const resp = await fetch("https://api.github.com/graphql", { const resp = await fetch("https://api.github.com/graphql", {
method: "POST", method: "POST",
headers: { headers: {
"Authorization": `bearer ${GITHUB_TOKEN}`, Authorization: `bearer ${GITHUB_TOKEN}`,
"Content-Type": "application/json" "Content-Type": "application/json",
}, },
body: JSON.stringify({ query, variables: { owner, name, number: prNumber } }) body: JSON.stringify({
query,
variables: { owner, name, number: prNumber },
}),
}); });
const json = await resp.json() as any; if (!resp.ok) {
const nodes = json.data.repository.pullRequest.files.nodes as { path: string }[]; const body = await resp.text();
return nodes.map(n => n.path); throw new Error(`GitHub GraphQL API error: ${resp.status} ${body}`);
}
const json = (await resp.json()) as any;
const nodes = json?.data?.repository?.pullRequest?.files?.nodes as
| { path: string }[]
| undefined;
if (!nodes || !Array.isArray(nodes)) return [];
return nodes.map((n) => n.path);
} }
async function formatPrMessage(evt: z.infer<typeof PullRequestSchema>): Promise<string> { function prUrlOf(pr: { html_url?: string; url?: string }) {
const files = await fetchPrFiles(evt.repository.full_name, evt.number); return pr.html_url ?? pr.url ?? "";
}
async function formatPrMessage(
evt: z.infer<typeof PullRequestSchema>,
): Promise<{ text: string; fileLink: string }> {
const pr = evt.pull_request;
const repo = evt.repository;
const files = await fetchPrFiles(repo.full_name, evt.number);
const lang = detectLanguage(files); const lang = detectLanguage(files);
return `Repository: [${evt.repository.full_name}](${evt.repository.html_url}) const prUrl = prUrlOf(pr);
Pull Request #: [${evt.number}](${evt.pull_request.url}) const fileLink = prUrl ? `${prUrl}/files` : repo.html_url;
Author: [${evt.pull_request.user.login}](${evt.pull_request.user.html_url}) const bodyText = pr.body ? pr.body : "_No description provided_";
Files Changed: ${evt.pull_request.changed_files}, +${evt.pull_request.additions}/- ${evt.pull_request.deletions} const text =
Likely Language: ${lang} `### Repository\n[${repo.full_name}](${repo.html_url})\n\n` +
Title: ${evt.pull_request.title} `**Pull Request #${evt.number}:** [${pr.title}](${prUrl || repo.html_url})\n\n` +
Description: ${evt.pull_request.body ?? "_None provided_"}` `**Author:** [${pr.user.login}](${pr.user.html_url})\n` +
`**Files Changed:** ${pr.changed_files}\n` +
`**Additions / Deletions:** +${pr.additions} / -${pr.deletions}\n` +
`**Language:** ${lang}\n\n` +
`**Description:**\n\`\`\`\n${bodyText}\n\`\`\``;
return { text, fileLink };
} }
function formatPushMessage(evt: z.infer<typeof PushSchema>): string { function formatPushMessage(evt: z.infer<typeof PushSchema>): {
text: string;
fileLink: string;
} {
const repo = evt.repository;
const c = evt.head_commit; const c = evt.head_commit;
if (!c) { if (!c) {
return `Repository: [${evt.repository.full_name}](${evt.repository.html_url}) const text = `### Repository\n[${repo.full_name}](${repo.html_url})\n\nPush event detected, but no head commit data available.`;
Push event but no head commit data.`; return { text, fileLink: repo.html_url };
} }
const added = c.added ?? [];
const modified = c.modified ?? [];
const removed = c.removed ?? [];
const details = [ const details = [
c.added.length ? `Added: ${c.added.join(", ")}` : "", added.length ? ` Added: ${added.join(", ")}` : "",
c.modified.length ? `Modified: ${c.modified.join(", ")}` : "", modified.length ? `✏️ Modified: ${modified.join(", ")}` : "",
c.removed.length ? `Removed: ${c.removed.join(", ")}` : "" removed.length ? `Removed: ${removed.join(", ")}` : "",
].filter(Boolean).join("\n"); ]
const lang = detectLanguage([...c.added, ...c.modified, ...c.removed]); .filter(Boolean)
return `Repository: [${evt.repository.full_name}](${evt.repository.html_url}) .join("\n");
Commit: [${c.id}](${c.url}) const lang = detectLanguage([...added, ...modified, ...removed]);
Author: ${c.author.name} <${c.author.email}> const fileLink = c.url;
Message: ${c.message} const text =
${details ? details + "\n" : ""}Detected Language: ${lang}`; `### Repository\n[${repo.full_name}](${repo.html_url})\n\n` +
`**Commit:** [${c.id}](${c.url})\n` +
`**Author:** ${c.author.name} <${c.author.email}>\n` +
`**Message:**\n\`\`\`\n${c.message}\n\`\`\`\n` +
(details ? `**Changes:**\n${details}\n` : "") +
`**Language:** ${lang}`;
return { text, fileLink };
} }
async function main(): Promise<void> { async function main(): Promise<void> {
const raw = await (await import("node:fs/promises")).readFile(EVENT_PATH, "utf-8"); const raw = await (
await import("node:fs/promises")
).readFile(EVENT_PATH, "utf-8");
const parsed = JSON.parse(raw); const parsed = JSON.parse(raw);
let message: string; let messageObj: { text: string; fileLink: string };
let topic: number; let topic: number;
if ("pull_request" in parsed) {
try {
const prEvt = PullRequestSchema.parse(parsed); const prEvt = PullRequestSchema.parse(parsed);
message = await formatPrMessage(prEvt); messageObj = await formatPrMessage(prEvt);
topic = TOPIC_PRS; topic = TOPIC_PRS;
} catch { } else {
const pushEvt = PushSchema.parse(parsed); const pushEvt = PushSchema.parse(parsed);
message = formatPushMessage(pushEvt); messageObj = formatPushMessage(pushEvt);
topic = TOPIC_COMMITS; topic = TOPIC_COMMITS;
} }
const repoUrl =
const keyboard = new InlineKeyboard().url("View on GitHub", (parsed.repository as any).html_url as string); (parsed.repository &&
await bot.api.sendMessage(GROUP_ID, message, { (parsed.repository.html_url ?? parsed.repository.url)) ||
"";
const keyboard = new InlineKeyboard()
.url("View on GitHub", repoUrl)
.row()
.url("View Files", messageObj.fileLink);
await bot.api.sendMessage(GROUP_ID, messageObj.text, {
parse_mode: "Markdown", parse_mode: "Markdown",
message_thread_id: topic, message_thread_id: topic,
reply_markup: keyboard reply_markup: keyboard,
}); });
process.exit(0); process.exit(0);
} }
main().catch(err => { main().catch((err) => {
console.error(err); console.error(err);
process.exit(1); process.exit(1);
}); });