219 lines
6.7 KiB
JavaScript
219 lines
6.7 KiB
JavaScript
import { graphql } from '@octokit/graphql'
|
|
|
|
import {
|
|
addItemsToProject,
|
|
isDocsTeamMember,
|
|
findFieldID,
|
|
findSingleSelectID,
|
|
generateUpdateProjectNextItemFieldMutation,
|
|
} from './projects.js'
|
|
|
|
async function getAllOpenPRs() {
|
|
let prsRemaining = true
|
|
let cursor
|
|
let prData = []
|
|
while (prsRemaining) {
|
|
const data = await graphql(
|
|
`
|
|
query ($organization: String!, $repo: String!) {
|
|
repository(name: $repo, owner: $organization) {
|
|
pullRequests(last: 100, states: OPEN${cursor ? ` before:"${cursor}"` : ''}) {
|
|
pageInfo{startCursor, hasPreviousPage},
|
|
nodes {
|
|
id
|
|
isDraft
|
|
reviewRequests(first: 10) {
|
|
nodes {
|
|
requestedReviewer {
|
|
... on Team {
|
|
name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
labels(first: 5) {
|
|
nodes {
|
|
name
|
|
}
|
|
}
|
|
reviews(first: 10) {
|
|
nodes {
|
|
onBehalfOf(first: 1) {
|
|
nodes {
|
|
name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
author {
|
|
login
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
{
|
|
organization: process.env.ORGANIZATION,
|
|
repo: process.env.REPO,
|
|
headers: {
|
|
authorization: `token ${process.env.TOKEN}`,
|
|
},
|
|
}
|
|
)
|
|
|
|
prsRemaining = data.repository.pullRequests.pageInfo.hasPreviousPage
|
|
cursor = data.repository.pullRequests.pageInfo.startCursor
|
|
prData = [...prData, ...data.repository.pullRequests.nodes]
|
|
}
|
|
|
|
return prData
|
|
}
|
|
|
|
async function run() {
|
|
// Get info about open github/github PRs
|
|
const prData = await getAllOpenPRs()
|
|
|
|
// Get the PRs that are:
|
|
// - not draft
|
|
// - not a train
|
|
// - are requesting a review by docs-reviewers
|
|
// - have not already been reviewed on behalf of docs-reviewers
|
|
const prs = prData.filter(
|
|
(pr) =>
|
|
!pr.isDraft &&
|
|
!pr.labels.nodes.find((label) => label.name === 'Deploy train 🚂') &&
|
|
pr.reviewRequests.nodes.find(
|
|
(requestedReviewers) => requestedReviewers.requestedReviewer?.name === process.env.REVIEWER
|
|
) &&
|
|
!pr.reviews.nodes
|
|
.flatMap((review) => review.onBehalfOf.nodes)
|
|
.find((behalf) => behalf.name === process.env.REVIEWER)
|
|
)
|
|
if (prs.length === 0) {
|
|
console.log('No PRs found. Exiting.')
|
|
return
|
|
}
|
|
|
|
const prIDs = prs.map((pr) => pr.id)
|
|
const prAuthors = prs.map((pr) => pr.author.login)
|
|
console.log(`PRs found: ${prIDs}`)
|
|
|
|
// Get info about the docs-content review board project
|
|
const projectData = await graphql(
|
|
`
|
|
query ($organization: String!, $projectNumber: Int!) {
|
|
organization(login: $organization) {
|
|
projectNext(number: $projectNumber) {
|
|
id
|
|
items(last: 100) {
|
|
nodes {
|
|
id
|
|
}
|
|
}
|
|
fields(first: 100) {
|
|
nodes {
|
|
id
|
|
name
|
|
settings
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
{
|
|
organization: process.env.ORGANIZATION,
|
|
projectNumber: parseInt(process.env.PROJECT_NUMBER),
|
|
headers: {
|
|
authorization: `token ${process.env.TOKEN}`,
|
|
},
|
|
}
|
|
)
|
|
|
|
// Get the project ID
|
|
const projectID = projectData.organization.projectNext.id
|
|
|
|
// Get the IDs of the last 100 items on the board.
|
|
// Until we have a way to check from a PR whether the PR is in a project,
|
|
// this is how we (roughly) avoid overwriting PRs that are already on the board.
|
|
// If we are overwriting items, query for more items.
|
|
const existingItemIDs = projectData.organization.projectNext.items.nodes.map((node) => node.id)
|
|
|
|
// Get the ID of the fields that we want to populate
|
|
const datePostedID = findFieldID('Date posted', projectData)
|
|
const reviewDueDateID = findFieldID('Review due date', projectData)
|
|
const statusID = findFieldID('Status', projectData)
|
|
const featureID = findFieldID('Feature', projectData)
|
|
const contributorTypeID = findFieldID('Contributor type', projectData)
|
|
const sizeTypeID = findFieldID('Size', projectData)
|
|
const authorID = findFieldID('Contributor', projectData)
|
|
|
|
// Get the ID of the single select values that we want to set
|
|
const readyForReviewID = findSingleSelectID('Ready for review', 'Status', projectData)
|
|
const hubberTypeID = findSingleSelectID('Hubber or partner', 'Contributor type', projectData)
|
|
const docsMemberTypeID = findSingleSelectID('Docs team', 'Contributor type', projectData)
|
|
|
|
// Add the PRs to the project
|
|
const itemIDs = await addItemsToProject(prIDs, projectID)
|
|
|
|
// If an item already existed on the project, the existing ID will be returned.
|
|
// Exclude existing items going forward.
|
|
// Until we have a way to check from a PR whether the PR is in a project,
|
|
// this is how we (roughly) avoid overwriting PRs that are already on the board
|
|
const newItemIDs = []
|
|
const newItemAuthors = []
|
|
itemIDs.forEach((id, index) => {
|
|
if (!existingItemIDs.includes(id)) {
|
|
newItemIDs.push(id)
|
|
newItemAuthors.push(prAuthors[index])
|
|
}
|
|
})
|
|
|
|
if (newItemIDs.length === 0) {
|
|
console.log('All found PRs are already on the project. Exiting.')
|
|
return
|
|
}
|
|
|
|
// Populate fields for the new project items
|
|
// (Using for...of instead of forEach since the function uses await)
|
|
for (const [index, itemID] of newItemIDs.entries()) {
|
|
const updateProjectNextItemMutation = generateUpdateProjectNextItemFieldMutation({
|
|
item: itemID,
|
|
author: newItemAuthors[index],
|
|
turnaround: 2,
|
|
feature: 'OpenAPI schema update',
|
|
})
|
|
const contributorType = (await isDocsTeamMember(newItemAuthors[index]))
|
|
? docsMemberTypeID
|
|
: hubberTypeID
|
|
console.log(`Populating fields for item: ${itemID} with author ${newItemAuthors[index]}`)
|
|
|
|
await graphql(updateProjectNextItemMutation, {
|
|
project: projectID,
|
|
statusID,
|
|
statusValueID: readyForReviewID,
|
|
datePostedID,
|
|
reviewDueDateID,
|
|
contributorTypeID,
|
|
contributorType,
|
|
sizeTypeID,
|
|
sizeType: '', // Although we aren't populating size, we are passing the variable so that we can use the shared mutation function
|
|
featureID,
|
|
authorID,
|
|
headers: {
|
|
authorization: `token ${process.env.TOKEN}`,
|
|
'GraphQL-Features': 'projects_next_graphql',
|
|
},
|
|
})
|
|
console.log('Done populating fields for item')
|
|
}
|
|
|
|
return newItemIDs
|
|
}
|
|
|
|
run().catch((error) => {
|
|
console.log(`#ERROR# ${error}`)
|
|
process.exit(1)
|
|
})
|