11import { graphql } from '@octokit/graphql'
22
3- // Given a list of PR/issue node IDs and a project node ID,
4- // adds the PRs/issues to the project
5- // and returns the node IDs of the project items
6- async function addItemsToProject ( items , project ) {
7- console . log ( `Adding ${ items } to project ${ project } ` )
8-
9- const mutations = items . map (
10- ( pr , index ) => `
11- pr_${ index } : addProjectNextItem(input: {
12- projectId: $project
13- contentId: "${ pr } "
14- }) {
15- projectNextItem {
16- id
17- }
18- }
19- `
20- )
21-
22- const mutation = `
23- mutation($project:ID!) {
24- ${ mutations . join ( ' ' ) }
25- }
26- `
27-
28- const newItems = await graphql ( mutation , {
29- project : project ,
30- headers : {
31- authorization : `token ${ process . env . TOKEN } ` ,
32- 'GraphQL-Features' : 'projects_next_graphql' ,
33- } ,
34- } )
35-
36- // The output of the mutation is
37- // {"pr_0":{"projectNextItem":{"id":ID!}},... }
38- // Pull out the ID for each new item
39- const newItemIDs = Object . entries ( newItems ) . map ( ( item ) => item [ 1 ] . projectNextItem . id )
40-
41- console . log ( `New item IDs: ${ newItemIDs } ` )
42-
43- return newItemIDs
44- }
45-
46- // Given a list of project item node IDs and a list of corresponding authors
47- // generates a GraphQL mutation to populate:
48- // - "Status" (as "Ready for review" option)
49- // - "Date posted" (as today)
50- // - "Review due date" (as today + 2 weekdays)
51- // - "Feature" (as "OpenAPI schema update")
52- // - "Contributor type" (as "Hubber or partner" option)
53- // Does not populate "Review needs" or "Size"
54- function generateUpdateProjectNextItemFieldMutation ( items , authors ) {
55- // Formats a date object into the required format for projects
56- function formatDate ( date ) {
57- return date . getFullYear ( ) + '-' + ( date . getMonth ( ) + 1 ) + '-' + date . getDate ( )
58- }
59-
60- // Calculate 2 weekdays from now (excluding weekends; not considering holidays)
61- const datePosted = new Date ( )
62- let daysUntilDue
63- switch ( datePosted . getDay ( ) ) {
64- case 0 : // Sunday
65- daysUntilDue = 3
66- break
67- case 6 : // Saturday
68- daysUntilDue = 4
69- break
70- default :
71- daysUntilDue = 2
72- }
73- const millisecPerDay = 24 * 60 * 60 * 1000
74- const dueDate = new Date ( datePosted . getTime ( ) + millisecPerDay * daysUntilDue )
75-
76- // Build the mutation for a single field
77- function generateMutation ( { index, item, fieldID, value, literal = false } ) {
78- let parsedValue
79- if ( literal ) {
80- parsedValue = `value: "${ value } "`
81- } else {
82- parsedValue = `value: ${ value } `
83- }
84-
85- return `
86- set_${ fieldID . substr ( 1 ) } _item_${ index } : updateProjectNextItemField(input: {
87- projectId: $project
88- itemId: "${ item } "
89- fieldId: ${ fieldID }
90- ${ parsedValue }
91- }) {
92- projectNextItem {
93- id
94- }
95- }
96- `
97- }
98-
99- // Build the mutation for all fields for all items
100- const mutations = items . map (
101- ( item , index ) => `
102- ${ generateMutation ( {
103- index : index ,
104- item : item ,
105- fieldID : '$statusID' ,
106- value : '$readyForReviewID' ,
107- } ) }
108- ${ generateMutation ( {
109- index : index ,
110- item : item ,
111- fieldID : '$datePostedID' ,
112- value : formatDate ( datePosted ) ,
113- literal : true ,
114- } ) }
115- ${ generateMutation ( {
116- index : index ,
117- item : item ,
118- fieldID : '$reviewDueDateID' ,
119- value : formatDate ( dueDate ) ,
120- literal : true ,
121- } ) }
122- ${ generateMutation ( {
123- index : index ,
124- item : item ,
125- fieldID : '$contributorTypeID' ,
126- value : '$hubberTypeID' ,
127- } ) }
128- ${ generateMutation ( {
129- index : index ,
130- item : item ,
131- fieldID : '$featureID' ,
132- value : 'OpenAPI schema update' ,
133- literal : true ,
134- } ) }
135- ${ generateMutation ( {
136- index : index ,
137- item : item ,
138- fieldID : '$authorID' ,
139- value : authors [ index ] ,
140- literal : true ,
141- } ) }
142- `
143- )
144-
145- // Build the full mutation
146- const mutation = `
147- mutation(
148- $project: ID!
149- $statusID: ID!
150- $readyForReviewID: String!
151- $datePostedID: ID!
152- $reviewDueDateID: ID!
153- $contributorTypeID: ID!
154- $hubberTypeID: String!
155- $featureID: ID!
156- $authorID: ID!
157-
158- ) {
159- ${ mutations . join ( ' ' ) }
160- }
161- `
162-
163- return mutation
164- }
3+ import {
4+ addItemsToProject ,
5+ isDocsTeamMember ,
6+ findFieldID ,
7+ findSingleSelectID ,
8+ generateUpdateProjectNextItemFieldMutation ,
9+ } from './projects.js'
16510
16611async function run ( ) {
16712 // Get info about the docs-content review board project
@@ -268,43 +113,6 @@ async function run() {
268113 // If we are overwriting items, query for more items.
269114 const existingItemIDs = data . organization . projectNext . items . nodes . map ( ( node ) => node . id )
270115
271- function findFieldID ( fieldName , data ) {
272- const field = data . organization . projectNext . fields . nodes . find (
273- ( field ) => field . name === fieldName
274- )
275-
276- if ( field && field . id ) {
277- return field . id
278- } else {
279- throw new Error (
280- `A field called "${ fieldName } " was not found. Check if the field was renamed.`
281- )
282- }
283- }
284-
285- function findSingleSelectID ( singleSelectName , fieldName , data ) {
286- const field = data . organization . projectNext . fields . nodes . find (
287- ( field ) => field . name === fieldName
288- )
289- if ( ! field ) {
290- throw new Error (
291- `A field called "${ fieldName } " was not found. Check if the field was renamed.`
292- )
293- }
294-
295- const singleSelect = JSON . parse ( field . settings ) . options . find (
296- ( field ) => field . name === singleSelectName
297- )
298-
299- if ( singleSelect && singleSelect . id ) {
300- return singleSelect . id
301- } else {
302- throw new Error (
303- `A single select called "${ singleSelectName } " for the field "${ fieldName } " was not found. Check if the single select was renamed.`
304- )
305- }
306- }
307-
308116 // Get the ID of the fields that we want to populate
309117 const datePostedID = findFieldID ( 'Date posted' , data )
310118 const reviewDueDateID = findFieldID ( 'Review due date' , data )
@@ -316,6 +124,7 @@ async function run() {
316124 // Get the ID of the single select values that we want to set
317125 const readyForReviewID = findSingleSelectID ( 'Ready for review' , 'Status' , data )
318126 const hubberTypeID = findSingleSelectID ( 'Hubber or partner' , 'Contributor type' , data )
127+ const docsMemberTypeID = findSingleSelectID ( 'Docs team' , 'Contributor type' , data )
319128
320129 // Add the PRs to the project
321130 const itemIDs = await addItemsToProject ( prIDs , projectID )
@@ -332,30 +141,33 @@ async function run() {
332141 }
333142
334143 // Populate fields for the new project items
335- // Note: Since there is not a way to check if a PR is already on the board,
336- // this will overwrite the values of PRs that are on the board
337- const updateProjectNextItemMutation = generateUpdateProjectNextItemFieldMutation (
338- newItemIDs ,
339- prAuthors
340- )
341- console . log ( `Populating fields for these items: ${ newItemIDs } ` )
342-
343- await graphql ( updateProjectNextItemMutation , {
344- project : projectID ,
345- statusID : statusID ,
346- readyForReviewID : readyForReviewID ,
347- datePostedID : datePostedID ,
348- reviewDueDateID : reviewDueDateID ,
349- contributorTypeID : contributorTypeID ,
350- hubberTypeID : hubberTypeID ,
351- featureID : featureID ,
352- authorID : authorID ,
353- headers : {
354- authorization : `token ${ process . env . TOKEN } ` ,
355- 'GraphQL-Features' : 'projects_next_graphql' ,
356- } ,
357- } )
358- console . log ( 'Done populating fields' )
144+ // (Using for...of instead of forEach since the function uses await)
145+ for ( const [ index , itemID ] of newItemIDs . entries ( ) ) {
146+ const updateProjectNextItemMutation = generateUpdateProjectNextItemFieldMutation ( {
147+ item : itemID ,
148+ author : prAuthors [ index ] ,
149+ turnaround : 2 ,
150+ } )
151+ const contributorType = isDocsTeamMember ( prAuthors [ index ] ) ? docsMemberTypeID : hubberTypeID
152+ console . log ( `Populating fields for item: ${ itemID } ` )
153+
154+ await graphql ( updateProjectNextItemMutation , {
155+ project : projectID ,
156+ statusID : statusID ,
157+ statusValueID : readyForReviewID ,
158+ datePostedID : datePostedID ,
159+ reviewDueDateID : reviewDueDateID ,
160+ contributorTypeID : contributorTypeID ,
161+ contributorType : contributorType ,
162+ featureID : featureID ,
163+ authorID : authorID ,
164+ headers : {
165+ authorization : `token ${ process . env . TOKEN } ` ,
166+ 'GraphQL-Features' : 'projects_next_graphql' ,
167+ } ,
168+ } )
169+ console . log ( 'Done populating fields for item' )
170+ }
359171
360172 return newItemIDs
361173}
0 commit comments