Files
zkldi_Tachi/github-bot/src/main.ts
T
zkldi 65cb74faa4 refactor: port github-bot to ESM
This is one of those annoying things. Updating OctoKit updated some transitive sindresorhus dependency which now forces onto ESM.

This proves to be a pretty annoying problem because you can't use CommonJS from inside ESM and vice versa. Somehow, as an industry, we've managed to invent "what color is your import" for NodeJS, which is a pretty brutal problem.

Anyway. I've made this specific package into an ESM module, and what it compiles to is a module now, too, instead of CommonJS. Luckily, because the github bot is so small and isolated, it means we have very little trouble doing this (and hopefully no brutal side effects).
2024-08-23 09:56:58 +00:00

152 lines
3.7 KiB
TypeScript

/* eslint-disable no-console */
import { ProcessEnv } from "./config.js";
import { App, createNodeMiddleware } from "@octokit/app";
import express from "express";
import fetch from "node-fetch";
import { URLSearchParams } from "url";
import type { Repository } from "@octokit/webhooks-types";
const app = new App({
appId: ProcessEnv.appId,
privateKey: ProcessEnv.privateKey,
webhooks: {
secret: ProcessEnv.webhookSecret,
},
oauth: {
clientId: ProcessEnv.clientID,
clientSecret: ProcessEnv.clientSecret,
},
});
/**
* Create a response that contains a link to the seeds diff viewer.
*/
function mkSeedDiffViewMsg(repo: string, sha: string, compareRepo: string, compareSHA: string) {
const params = new URLSearchParams({
repo: ConvertGitHubURL(repo),
sha,
compareRepo: ConvertGitHubURL(compareRepo),
compareSHA,
});
return `\nA commit has changed the seeds. [View the diff here.](https://boku.tachi.ac/utils/seeds?${params.toString()})`;
}
function ConvertGitHubURL(url: string) {
return url.replace("https://api.github.com/repos/", "GitHub:");
}
async function sendMsg(message: string, octokit: any, repo: Repository, issue: number) {
await octokit.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", {
owner: repo.owner.login,
repo: repo.name,
issue_number: issue,
body: message,
});
}
app.webhooks.on(["pull_request.opened", "pull_request.edited"], async ({ octokit, payload }) => {
try {
const filesChanged = (await fetch(
`https://api.github.com/repos/zkrising/Tachi/pulls/${payload.number}/files`
).then((r) => r.json())) as Array<{ filename: string }>;
// if any file modified in this pr is a collection
if (filesChanged.some((k) => k.filename.startsWith("seeds/collections"))) {
// post a link to the diff viewer in the PR comments.
await sendMsg(
mkSeedDiffViewMsg(
payload.pull_request.base.repo.url,
payload.pull_request.base.sha,
payload.pull_request.head.repo!.url,
payload.pull_request.head.sha
),
octokit,
payload.repository as any,
payload.pull_request.number
);
}
} catch (err) {
await sendMsg(
`I failed horribly figuring out whether this was a seeds diff or not. I'm sorry!
*****
Reason
\`\`\`
${err}
\`\`\`
*****
${mkSeedDiffViewMsg(
payload.pull_request.base.repo.url,
payload.pull_request.base.sha,
payload.pull_request.head.repo!.url,
payload.pull_request.head.sha
)}`,
octokit,
payload.repository as any,
payload.pull_request.number
);
}
});
app.webhooks.on(["issue_comment.created"], async ({ octokit, payload }) => {
const body = payload.comment.body.trim();
if (body.startsWith("+bot")) {
const cmd = body
.split("\n")[0]!
.split(/\s+/u)[1]
?.replace(/[^a-z]/u, "");
switch (cmd) {
case "ping": {
await sendMsg("pong!", octokit, payload.repository as any, payload.issue.number);
break;
}
case "diff": {
const pr = (
await octokit.request("GET /repos/{owner}/{repo}/pulls/{pull_number}", {
owner: payload.repository.owner.login,
repo: payload.repository.name,
pull_number: payload.issue.number,
})
).data;
await sendMsg(
mkSeedDiffViewMsg(
pr.base.repo.url,
pr.base.sha,
pr.head.repo?.url ?? "unknown-url",
pr.head.sha
),
octokit,
payload.repository as any,
pr.number
);
break;
}
default:
await sendMsg(
`No idea what to do with command \`${cmd}\`, sorry!`,
octokit,
payload.repository as any,
payload.issue.number
);
}
}
});
const serverMiddleware = createNodeMiddleware(app);
const expressApp = express();
expressApp.use(serverMiddleware);
console.log(`Listening on port ${ProcessEnv.port}.`);
expressApp.listen(ProcessEnv.port);