Skip to content

Commit c218f16

Browse files
KianNHdaisyfaithauma
authored andcommitted
[Docs Site] Comment matched CODEOWNERS entries on PRs (#22369)
* [Docs Site] Comment matched CODEOWNERS entries on PRs * fix order * add token * wrap pattern in backticks too * continue on error
1 parent 54367cf commit c218f16

File tree

3 files changed

+104
-0
lines changed

3 files changed

+104
-0
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ jobs:
2828
key: static
2929

3030
- run: npm ci
31+
32+
- run: npx tsx bin/post-codeowners-comment/index.ts
33+
continue-on-error: true
34+
env:
35+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
3137
- run: npm run check
3238

3339
- uses: reviewdog/action-eslint@v1
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const GITHUB_ACTIONS_BOT_ID = 41898282;
2+
export const COMMENT_PREFIX =
3+
"This pull request requires reviews from **CODEOWNERS** as it changes files that match the following patterns:";
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import * as core from "@actions/core";
2+
import * as github from "@actions/github";
3+
import type { PullRequestEvent } from "@octokit/webhooks-types";
4+
5+
import { loadOwners, matchFile } from "codeowners-utils";
6+
import { GITHUB_ACTIONS_BOT_ID, COMMENT_PREFIX } from "./constants.ts";
7+
8+
async function run(): Promise<void> {
9+
try {
10+
if (!process.env.GITHUB_TOKEN) {
11+
core.setFailed(`Could not find GITHUB_TOKEN in env`);
12+
process.exit();
13+
}
14+
15+
const octokit = github.getOctokit(process.env.GITHUB_TOKEN);
16+
const payload = github.context.payload as PullRequestEvent;
17+
18+
const { owner, repo } = github.context.repo;
19+
const pullRequestNumber = payload.number;
20+
21+
const files = await octokit.paginate(octokit.rest.pulls.listFiles, {
22+
owner,
23+
repo,
24+
pull_number: pullRequestNumber,
25+
});
26+
27+
const codeowners = await loadOwners(process.cwd());
28+
29+
if (!codeowners) {
30+
throw new Error("Unable to load CODEOWNERS file.");
31+
}
32+
33+
const matchedPatterns = [
34+
...new Set(
35+
files.flatMap((file) => matchFile(file.filename, codeowners) ?? []),
36+
),
37+
];
38+
39+
const { data: comments } = await octokit.rest.issues.listComments({
40+
owner,
41+
repo,
42+
issue_number: pullRequestNumber,
43+
per_page: 100,
44+
});
45+
46+
const existingComment = comments.find(
47+
(comment) =>
48+
comment.user?.id === GITHUB_ACTIONS_BOT_ID &&
49+
comment.body?.includes(COMMENT_PREFIX),
50+
);
51+
52+
if (existingComment) {
53+
core.info(`Found existing comment with ID ${existingComment.id}`);
54+
} else {
55+
core.info(`No existing comment found`);
56+
}
57+
58+
const comment = [
59+
COMMENT_PREFIX,
60+
"| Pattern | Owners |",
61+
"| ------- | ------ |",
62+
...matchedPatterns.map(
63+
(pattern) =>
64+
`| \`${pattern.pattern}\` | ${pattern.owners.map((owner) => `\`${owner}\``).join(", ")} |`,
65+
),
66+
].join("\n");
67+
68+
if (existingComment) {
69+
core.info(
70+
`Updating ${existingComment.id} with ${JSON.stringify(comment)}`,
71+
);
72+
await octokit.rest.issues.updateComment({
73+
owner,
74+
repo,
75+
comment_id: existingComment.id,
76+
body: comment,
77+
});
78+
} else {
79+
core.info(`Creating new comment with ${JSON.stringify(comment)}`);
80+
await octokit.rest.issues.createComment({
81+
owner,
82+
repo,
83+
issue_number: pullRequestNumber,
84+
body: comment,
85+
});
86+
}
87+
} catch (error) {
88+
if (error instanceof Error) {
89+
core.setFailed(error.message);
90+
}
91+
process.exit();
92+
}
93+
}
94+
95+
run();

0 commit comments

Comments
 (0)