Skip to content

Commit d43388a

Browse files
committed
feat(ci): request reviews from API experts
1 parent c39cd36 commit d43388a

File tree

54 files changed

+204
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+204
-4
lines changed

.github/CODEOWNERS

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,3 @@ docs @nodejs/nodejs-website @nodejs/web-infra
3838
# Node.js Release Blog Posts
3939
apps/site/pages/en/blog/release @nodejs/releasers
4040
apps/site/pages/en/blog/announcements @nodejs/releasers
41-
42-
# Specific content
43-
apps/site/pages/en/learn/getting-started/security-best-practices.md @nodejs/security-wg
44-
apps/site/pages/en/learn/typescript @nodejs/typescript

.github/reviewers.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"fs": "<at>nodejs/fs",
3+
"timers": "<at>nodejs/timers",
4+
"events": "<at>nodejs/events",
5+
"repl": "<at>nodejs/repl",
6+
"diagnostics": "<at>nodejs/diagnostics",
7+
"undici": "<at>nodejs/undici",
8+
"npm": "<at>nodejs/npm",
9+
"security": "<at>nodejs/security-wg",
10+
"n-api": "<at>nodejs/addon-api",
11+
"test": "<at>nodejs/test_runner",
12+
"typescript": "<at>nodejs/typescript"
13+
}

.github/scripts/get-reviewers.mjs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import fs from 'fs';
2+
3+
export default async function (core, filesList) {
4+
// Load reviewers mapping
5+
const reviewersMap = JSON.parse(
6+
fs.readFileSync('.github/reviewers.json', 'utf8')
7+
);
8+
9+
// Parse the file list from the input
10+
const files = filesList.trim().split(' ').filter(Boolean);
11+
12+
// Track reviewers we need to mention
13+
const reviewersToMention = new Set();
14+
15+
// Process each file
16+
for (const file of files) {
17+
const content = fs.readFileSync(file, 'utf8');
18+
const apiValues = extractApisFromFrontmatter(content);
19+
20+
if (apiValues && apiValues.length > 0) {
21+
for (const apiValue of apiValues) {
22+
if (reviewersMap[apiValue]) {
23+
reviewersToMention.add(`- [ ] ${reviewersMap[apiValue]}`);
24+
}
25+
}
26+
}
27+
}
28+
29+
// Set outputs
30+
const reviewersList = Array.from(reviewersToMention);
31+
core.setOutput('found', reviewersList.length > 0);
32+
core.setOutput('reviewers', reviewersList.join('\n'));
33+
}
34+
35+
/**
36+
* Extract API values from frontmatter
37+
* @returns {string[]} Array of API values found in frontmatter
38+
*/
39+
function extractApisFromFrontmatter(content) {
40+
if (!content.trimStart().startsWith('---')) {
41+
return [];
42+
}
43+
44+
const firstMarker = content.indexOf('---');
45+
const secondMarker = content.indexOf('---', firstMarker + 3);
46+
47+
if (firstMarker === -1 || secondMarker === -1) {
48+
return [];
49+
}
50+
51+
const frontmatterContent = content.substring(firstMarker + 3, secondMarker);
52+
53+
// Find the api: line
54+
const apiLineRegex = /^\s*api\s*:\s*(.+)$/m;
55+
const match = apiLineRegex.exec(frontmatterContent);
56+
57+
if (!match) return [];
58+
59+
// Extract all API values, handling various formats
60+
// This splits by commas and trims each value
61+
const apiValues = match[1]
62+
.split(',')
63+
.map(value => value.trim())
64+
.filter(Boolean);
65+
66+
return apiValues;
67+
}

.github/workflows/request-review.yml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: Request Reviewers
2+
3+
on:
4+
# DEMO
5+
pull_request:
6+
branches:
7+
- main
8+
# TMP
9+
- add-reviewer-support
10+
types:
11+
- opened
12+
- reopened
13+
- synchronize
14+
paths:
15+
- "apps/site/pages/en/**/*.md"
16+
- "apps/site/pages/en/**/*.mdx"
17+
18+
# Cancel any runs on the same branch
19+
concurrency:
20+
group: ${{ github.workflow }}-${{ github.ref }}
21+
cancel-in-progress: true
22+
23+
permissions:
24+
actions: read
25+
26+
jobs:
27+
request-review:
28+
name: Request Review from API Experts
29+
runs-on: ubuntu-latest
30+
31+
permissions:
32+
# This permission is required by `thollander/actions-comment-pull-request`
33+
pull-requests: write
34+
35+
steps:
36+
- name: Harden Runner
37+
uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
38+
with:
39+
egress-policy: audit
40+
41+
- name: Checkout Repo
42+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
43+
with:
44+
fetch-depth: 0
45+
46+
- name: Get changed files
47+
id: changed-files
48+
run: |
49+
FILES=$(git diff --name-only $BASE $HEAD | grep -E '^apps/site/pages/en/.*\.(md|mdx)$')
50+
echo $FILES
51+
echo "files<<EOF" >> $GITHUB_OUTPUT
52+
echo $FILES >> $GITHUB_OUTPUT
53+
echo "EOF" >> $GITHUB_OUTPUT
54+
env:
55+
BASE: ${{ github.event.pull_request.base.sha }}
56+
HEAD: ${{ github.event.pull_request.head.sha }}
57+
58+
- name: Get Reviewers
59+
id: reviewers
60+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
61+
with:
62+
script: |
63+
const { default: reviewers } = await import("${{github.workspace}}/.github/scripts/get-reviewers.mjs");
64+
reviewers(core, process.env.PR_FILES);
65+
env:
66+
PR_FILES: ${{ steps.changed-files.outputs.files }}
67+
68+
- uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 # v3.0.0
69+
if: steps.reviewers.outputs.found == 'true'
70+
with:
71+
message: |
72+
Requesting a review from the following teams:
73+
${{ steps.reviewers.outputs.reviewers }}
74+
comment-tag: request_review

apps/site/pages/en/learn/asynchronous-work/asynchronous-flow-control.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
title: Asynchronous flow control
33
layout: learn
44
authors: aug2uag, ovflowd
5+
api: timers, events
56
---
67

78
# Asynchronous flow control

apps/site/pages/en/learn/asynchronous-work/discover-javascript-timers.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
title: Discover JavaScript Timers
33
layout: learn
44
authors: flaviocopes, MylesBorins, LaRuaNa, amiller-gh, ahmadawais, ovflowd
5+
api: timers
56
---
67

78
# Discover JavaScript Timers

apps/site/pages/en/learn/asynchronous-work/dont-block-the-event-loop.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Don't Block the Event Loop (or the Worker Pool)
33
layout: learn
4+
api: events, workers
45
---
56

67
# Don't Block the Event Loop (or the Worker Pool)

apps/site/pages/en/learn/asynchronous-work/event-loop-timers-and-nexttick.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: The Node.js Event Loop
33
layout: learn
4+
api: timers, events
45
---
56

67
# The Node.js Event Loop

apps/site/pages/en/learn/asynchronous-work/overview-of-blocking-vs-non-blocking.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
title: Overview of Blocking vs Non-Blocking
33
layout: learn
44
authors: ovflowd, HassanBahati
5+
api: events
56
---
67

78
# Overview of Blocking vs Non-Blocking

apps/site/pages/en/learn/asynchronous-work/the-nodejs-event-emitter.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
title: The Node.js Event emitter
33
layout: learn
44
authors: flaviocopes, MylesBorins, fhemberger, LaRuaNa, ahmadawais, ovflowd
5+
api: events
56
---
67

78
# The Node.js Event emitter

0 commit comments

Comments
 (0)