Files
public-apis/scripts/pr-review-automation.js
Juan Diaz 274218e3fb Improve PR Review Automation with better error handling and permissions (#563)
* Add PR review automation workflow and script

closes #559

* Improve PR review automation with better error handling and permissions
2025-07-11 16:04:20 -04:00

132 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { context, getOctokit } = require("@actions/github");
const fs = require("fs");
const token = process.env.GITHUB_TOKEN;
const octokit = getOctokit(token);
async function run() {
try {
const pr = context.payload.pull_request;
const { owner, repo } = context.repo;
const prNumber = pr.number;
console.log(`Working with repository: ${owner}/${repo}`);
console.log(`PR number: ${prNumber}`);
console.log(`PR author: ${pr.user.login}`);
console.log(`Head repo: ${pr.head.repo.full_name}`);
console.log(`Base repo: ${pr.base.repo.full_name}`);
const filesChanged = await octokit.rest.pulls.listFiles({
owner,
repo,
pull_number: prNumber,
});
const comments = [];
// Check 1: New API links in README.md
const readmeFile = filesChanged.data.find(
(file) => file.filename.toLowerCase() === "readme.md"
);
if (readmeFile) {
console.log("README.md modified. Checking for new API links...");
const newLinks = await checkForNewApiLinks(owner, repo, pr);
if (newLinks.length > 0) {
const linkComment =
newLinks.length === 1
? `**API link:** ${newLinks[0]}`
: [
"**New API links:**",
"",
...newLinks.map((link) => `- ${link}`),
].join("\n");
comments.push(linkComment);
}
}
// Check 2: Edits to /db folder
const dbFiles = filesChanged.data.filter((file) =>
file.filename.startsWith("db/")
);
if (dbFiles.length > 0) {
console.log(
`DB folder modifications detected in ${dbFiles.length} file(s)`
);
const dbWarning =
"Thanks for your contribution!\n❗ **Warning:** The `/db` folder is auto-generated, so please do not edit it. Changes related to public APIs should happen in the `README.md` file. Read the [contribution guidelines](https://github.com/marcelscruz/public-apis/blob/main/CONTRIBUTING.md) for more details.";
comments.push(dbWarning);
}
// Post all comments as a single comment
if (comments.length > 0) {
const finalComment = comments.join("\n\n---\n\n");
await octokit.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: finalComment,
});
console.log("Comment posted with all checks.");
} else {
console.log("No issues found in this PR.");
}
} catch (error) {
console.error("Error in PR review automation:", error);
// Don't exit with error code to avoid failing the entire workflow
// Just log the error and continue
}
}
async function checkForNewApiLinks(owner, repo, pr) {
const baseRes = await octokit.rest.repos.getContent({
owner,
repo,
path: "README.md",
ref: pr.base.ref,
});
const headRes = await octokit.rest.repos.getContent({
owner,
repo,
path: "README.md",
ref: pr.head.ref,
});
const decode = (res) =>
Buffer.from(res.data.content, "base64").toString("utf8");
const baseContent = decode(baseRes);
const headContent = decode(headRes);
const baseLinks = new Set(
[...baseContent.matchAll(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g)].map(
(m) => m[2]
)
);
const headLinks = new Set(
[...headContent.matchAll(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g)].map(
(m) => m[2]
)
);
const newLinks = [...headLinks].filter((link) => !baseLinks.has(link));
console.log(`Base links found: ${baseLinks.size}`);
console.log(`Head links found: ${headLinks.size}`);
console.log(`New links found: ${newLinks.length}`);
if (newLinks.length > 0) {
console.log("New links:", newLinks);
}
return newLinks;
}
run().catch((error) => {
console.error(error);
process.exit(1);
});