Skip to content

Commit 4460e0c

Browse files
committed
meta: request reviews from github actions
1 parent 177b8b9 commit 4460e0c

File tree

3 files changed

+119
-18
lines changed

3 files changed

+119
-18
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Handle PRs
2+
3+
on:
4+
pull_request_target:
5+
types: [opened]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
issues: write
11+
12+
jobs:
13+
main:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
18+
name: Checkout default branch
19+
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
20+
name: Make initial comment
21+
with:
22+
script: |
23+
const initialCommentBuilder = require('${{ github.workspace }}/tools/actions/pr-open.js');
24+
await initialCommentBuilder(github, context);
25+
- uses: nodejs/node-pr-labeler@d4cf1b8b9f23189c37917000e5e17e796c770a6b # v1
26+
with:
27+
repo-token: ${{ secrets.GH_USER_TOKEN }}
28+
configuration-path: .github/label-pr-config.yml

.github/workflows/label-pr.yml

Lines changed: 0 additions & 18 deletions
This file was deleted.

tools/actions/pr-open.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
'use strict';
2+
3+
module.exports = async (client, context) => {
4+
function globToRegex(glob) {
5+
const patterns = {
6+
'*': '([^\\/]+)',
7+
'**': '(.+\\/)?([^\\/]+)',
8+
'**/': '(.+\\/)',
9+
};
10+
11+
const escapedGlob = glob.replace(/\./g, '\\.').replace(/\*\*$/g, '(.+)');
12+
const regexString = '^(' + escapedGlob.replace(/\*\*\/|\*\*|\*/g, (match) => patterns[match] || '') + ')$';
13+
return new RegExp(regexString);
14+
}
15+
16+
class CodeOwners {
17+
constructor(fileContent) {
18+
this.owners = fileContent.split('\n').map((line) => line.trim())
19+
.filter((line) => line && !line.startsWith('#'))
20+
.map((line) => {
21+
const [path, ...owners] = line.split(/\s+/);
22+
return { path: globToRegex(path), owners };
23+
});
24+
}
25+
26+
getOwners(filePath) {
27+
const normalizedPath = filePath.startsWith('/') ? filePath : `/${filePath}`;
28+
return this.owners
29+
.filter(({ path }) => path.test(normalizedPath))
30+
.flatMap(({ owners }) => owners);
31+
}
32+
}
33+
34+
async function getChangedFiles(base, head) {
35+
const { data } = await client.rest.repos.compareCommits({
36+
owner: context.repo.owner,
37+
repo: context.repo.repo,
38+
base,
39+
head,
40+
});
41+
return data.files.map((file) => file.filename);
42+
}
43+
44+
async function getCodeOwners() {
45+
const { data } = await client.rest.repos.getContent({
46+
owner: context.repo.owner,
47+
repo: context.repo.repo,
48+
path: '.github/CODEOWNERS',
49+
});
50+
51+
const content = Buffer.from(data.content, 'base64').toString('utf8');
52+
return new CodeOwners(content);
53+
}
54+
55+
async function makeInitialComment(changedFiles) {
56+
const codeOwners = await getCodeOwners();
57+
58+
const owners = new Set();
59+
changedFiles.forEach((file) => {
60+
codeOwners.getOwners(file).forEach((owner) => owners.add(owner));
61+
});
62+
63+
const ownersList = Array.from(owners).map((owner) => `- ${owner}`).join('\n');
64+
65+
const body =
66+
'Hi 👋! Thank you for submitting this pull-request!\n\n' +
67+
'According to the CODEOWNERS file, the following people are responsible for' +
68+
"reviewing changes to the files you've modified:\n\n" +
69+
ownersList + '\n\n' +
70+
'They, along with other project maintainers, will be notified of your pull request.' +
71+
'Please be patient and wait for them to review your changes.\n\n' +
72+
"If you have any questions, please don't hesitate to ask!";
73+
74+
return client.rest.issues.createComment({
75+
owner: context.repo.owner,
76+
repo: context.repo.repo,
77+
issue_number: context.payload.pull_request.number,
78+
body: body,
79+
});
80+
}
81+
82+
const base = context.payload.pull_request?.base?.sha;
83+
const head = context.payload.pull_request?.head?.sha;
84+
85+
if (!base || !head) {
86+
throw new Error('Cannot get base or head commit');
87+
}
88+
89+
const changedFiles = await getChangedFiles(base, head);
90+
await makeInitialComment(changedFiles);
91+
};

0 commit comments

Comments
 (0)