Skip to content

Commit c9263b6

Browse files
authored
chore: define and parse default reviewers from team_members comment in CODEOWNERS (#8683)
* chore: parse individual default reviewers from CODEOWNERS for load-balancing * chore: define and parse default reviewers from team_members comment in CODEOWNERS * chore: fallback to default team reviewers if path-routed partner team assignment fails * chore: fetch CODEOWNERS using PR head SHA to read correct team_members definition * chore: fix typo in reviewer username in CODEOWNERS * Update codeowners to reflect code ownership
1 parent e78cc50 commit c9263b6

2 files changed

Lines changed: 54 additions & 40 deletions

File tree

.github/CODEOWNERS

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
66

77

8-
# The yoshi-nodejs team is the default owner for nodejs repositories.
8+
# The cloud sdk nodejs team is the default owner for nodejs repositories.
9+
# team_members: @pearigee @feywind @danieljbruce @shivanee-p
910
* @googleapis/cloud-sdk-nodejs-team
1011
/handwritten/bigquery @googleapis/bigquery-team
1112
/handwritten/cloud-profiler @googleapis/cloud-profiler-team
1213
/handwritten/storage @googleapis/gcs-team
1314
/handwritten/firestore @googleapis/firestore-team
1415
/handwritten/spanner @googleapis/spanner-team
1516
/handwritten/bigquery-storage @googleapis/bigquery-team
16-
/handwritten/pubsub @googleapis/pubsub-team
17-
/handwritten/bigtable @googleapis/bigtable-team
1817
/core/packages/google-auth-library-nodejs @googleapis/aion-team

.github/workflows/assign-reviewers.yml

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -91,29 +91,58 @@ jobs:
9191
}
9292
}
9393
94+
let assigned = false;
9495
if (assignedTeams.size > 0) {
9596
const teamReviewers = Array.from(assignedTeams);
9697
console.log(`PR contains changes matching specific routes. Requesting review from: ${teamReviewers.join(', ')}`);
97-
await github.rest.pulls.requestReviewers({
98-
owner: context.repo.owner,
99-
repo: context.repo.repo,
100-
pull_number: context.payload.pull_request.number,
101-
team_reviewers: teamReviewers,
102-
});
103-
} else {
104-
// Route to cloud-sdk-nodejs-team members with load balancing
105-
console.log("Requesting review from a member of cloud-sdk-nodejs-team using load balancing.");
10698
try {
107-
const { data: members } = await github.rest.teams.listMembersInOrg({
108-
org: 'googleapis',
109-
team_slug: 'cloud-sdk-nodejs-team',
99+
await github.rest.pulls.requestReviewers({
100+
owner: context.repo.owner,
101+
repo: context.repo.repo,
102+
pull_number: context.payload.pull_request.number,
103+
team_reviewers: teamReviewers,
110104
});
111-
112-
const memberLogins = members
113-
.map(m => m.login)
114-
.filter(login => login !== author);
105+
assigned = true;
106+
} catch (err) {
107+
console.error(`Failed to assign route-specific team reviewers (${teamReviewers.join(', ')}):`, err.message || err);
108+
console.log("Falling back to default team members.");
109+
}
110+
}
111+
112+
if (!assigned) {
113+
console.log("Fetching .github/CODEOWNERS to identify default reviewers...");
114+
let defaultReviewers = [];
115+
try {
116+
const { data: codeownersData } = await github.rest.repos.getContent({
117+
owner: context.repo.owner,
118+
repo: context.repo.repo,
119+
path: '.github/CODEOWNERS',
120+
ref: context.payload.pull_request.head.sha,
121+
});
122+
const content = Buffer.from(codeownersData.content, 'base64').toString('utf-8');
123+
const lines = content.split('\n');
124+
for (const line of lines) {
125+
const trimmed = line.trim();
126+
if (trimmed.startsWith('#')) {
127+
const commentContent = trimmed.substring(1).trim();
128+
if (commentContent.startsWith('team_members:')) {
129+
const listPart = commentContent.substring('team_members:'.length).trim();
130+
const parts = listPart.split(/\s+/);
131+
defaultReviewers = parts
132+
.filter(p => p.startsWith('@'))
133+
.map(p => p.substring(1))
134+
.filter(login => login !== author);
135+
break;
136+
}
137+
}
138+
}
139+
} catch (err) {
140+
console.error("Failed to read or parse CODEOWNERS:", err);
141+
}
115142
116-
if (memberLogins.length > 0) {
143+
if (defaultReviewers.length > 0) {
144+
console.log(`Found default reviewers: ${defaultReviewers.join(', ')}. Load balancing among them.`);
145+
try {
117146
// Retrieve active open PRs to calculate load
118147
const { data: openPRs } = await github.rest.pulls.list({
119148
owner: context.repo.owner,
@@ -123,7 +152,7 @@ jobs:
123152
});
124153
125154
const loadMap = {};
126-
for (const member of memberLogins) {
155+
for (const member of defaultReviewers) {
127156
loadMap[member] = 0;
128157
}
129158
@@ -151,7 +180,7 @@ jobs:
151180
// Find members with the minimum load
152181
let minLoad = Infinity;
153182
let selectedReviewers = [];
154-
for (const member of memberLogins) {
183+
for (const member of defaultReviewers) {
155184
const load = loadMap[member];
156185
if (load < minLoad) {
157186
minLoad = load;
@@ -169,25 +198,11 @@ jobs:
169198
repo: context.repo.repo,
170199
pull_number: context.payload.pull_request.number,
171200
reviewers: [leastLoadedReviewer],
172-
team_reviewers: ['cloud-sdk-nodejs-team'],
173-
});
174-
} else {
175-
console.log("No other members found in cloud-sdk-nodejs-team. Requesting team review only.");
176-
await github.rest.pulls.requestReviewers({
177-
owner: context.repo.owner,
178-
repo: context.repo.repo,
179-
pull_number: context.payload.pull_request.number,
180-
team_reviewers: ['cloud-sdk-nodejs-team'],
181201
});
202+
} catch (err) {
203+
console.error("Failed to assign reviewers using load balancing:", err);
182204
}
183-
} catch (err) {
184-
console.error("Failed to fetch team members or assign reviewers:", err);
185-
// Fallback to just requesting the team review
186-
await github.rest.pulls.requestReviewers({
187-
owner: context.repo.owner,
188-
repo: context.repo.repo,
189-
pull_number: context.payload.pull_request.number,
190-
team_reviewers: ['cloud-sdk-nodejs-team'],
191-
});
205+
} else {
206+
console.warn("No default reviewers found in CODEOWNERS (or they only contained teams/author).");
192207
}
193208
}

0 commit comments

Comments
 (0)