scripts/prioritization/assign-r5-priority.js (86 lines of code) (raw):
/**
* Monitors open PRs once daily during weekdays to identify stale community review requests. When a PR
* with the community review label hasn't been updated for the specified threshold
* period (default 21 days), it's assigned R5 priority. These PRs are added to the
* project board and set to Ready status to ensure visibility of long-pending
* community reviews.
*/
const { PRIORITIES, LABELS, STATUS, DAYS_THRESHOLD, ...PROJECT_CONFIG } = require("./project-config");
const {
updateProjectField,
updateProjectDateField,
addItemToProject,
fetchProjectFields,
fetchOpenPullRequests,
fetchProjectItem,
} = require('./project-api');
const MS_PER_DAY = 1000 * 60 * 60 * 24;
module.exports = async ({ github }) => {
let allPRs = [];
let hasNextPage = true;
let cursor = null;
// Fetch all PRs using pagination
while (hasNextPage) {
const result = await fetchOpenPullRequests({
github,
org: PROJECT_CONFIG.org,
repo: PROJECT_CONFIG.repo,
cursor: cursor,
});
const pullRequests = result.organization.repository.pullRequests;
allPRs = allPRs.concat(pullRequests.nodes);
// Update pagination info
hasNextPage = pullRequests.pageInfo.hasNextPage;
cursor = pullRequests.pageInfo.endCursor;
}
console.log(`Total PRs fetched: ${allPRs.length}`);
// Get project fields
const projectFields = await fetchProjectFields({
github,
org: PROJECT_CONFIG.org,
number: PROJECT_CONFIG.projectNumber
});
const priorityField = projectFields.organization.projectV2.fields.nodes.find(
(field) => field.id === PROJECT_CONFIG.priorityFieldId
);
const statusField = projectFields.organization.projectV2.fields.nodes.find(
(field) => field.id === PROJECT_CONFIG.statusFieldId
);
const r5OptionId = priorityField.options.find(
(option) => option.name === PRIORITIES.R5
)?.id;
const readyStatusId = statusField.options.find(
(option) => option.name === STATUS.READY
)?.id;
for (const pr of allPRs) {
const labels = pr.labels.nodes.map((l) => l.name);
const isDraft = pr.draft === true;
// Skip draft PRs
if (isDraft) {
console.log(`Skipping draft PR #${pr.number}`);
continue;
}
const hasExemptionOrClarification = labels.some(label =>
[LABELS.CLARIFICATION_REQUESTED, LABELS.EXEMPTION_REQUESTED].includes(label)
);
// Skip if PR doesn't have community review label or has exemption/clarification
if (!labels.includes(LABELS.COMMUNITY_REVIEW) || hasExemptionOrClarification) {
continue;
}
const lastUpdated = new Date(pr.updatedAt);
const daysSinceUpdate = (Date.now() - lastUpdated) / MS_PER_DAY;
// Skip if PR update is within the days threshold
if (daysSinceUpdate <= DAYS_THRESHOLD) {
continue;
}
console.log(`Processing PR #${pr.number} for ${PRIORITIES.R5} priority consideration`);
try {
// Get all projects the PR added to
const result = await fetchProjectItem({
github,
contentId: pr.id
});
// Filter specific project
const projectItem = result?.node?.projectItems?.nodes
?.find(item => item.project.id === PROJECT_CONFIG.projectId);
// Skip if PR is already in project
if (projectItem) {
console.log(`PR #${pr.number} is already in project. Skipping.`);
continue;
}
// Add new PR to project with R5 priority
console.log(`Adding PR #${pr.number} to project with ${PRIORITIES.R5} priority`);
const addResult = await addItemToProject({
github,
projectId: PROJECT_CONFIG.projectId,
contentId: pr.id,
});
// Set priority, Ready status and current date for new items
await Promise.all([
updateProjectField({
github,
projectId: PROJECT_CONFIG.projectId,
itemId: addResult.addProjectV2ItemById.item.id,
fieldId: PROJECT_CONFIG.priorityFieldId,
value: r5OptionId,
}),
updateProjectField({
github,
projectId: PROJECT_CONFIG.projectId,
itemId: addResult.addProjectV2ItemById.item.id,
fieldId: PROJECT_CONFIG.statusFieldId,
value: readyStatusId,
}),
updateProjectDateField({
github,
projectId: PROJECT_CONFIG.projectId,
itemId: itemId,
fieldId: PROJECT_CONFIG.addedOnFieldId,
date: new Date().toISOString(),
})
]);
} catch (error) {
console.error(`Error processing PR #${pr.number}:`, error);
continue;
}
}
}