1
+ import { ProbotOctokit } from "probot" ;
2
+ import {
3
+ getProjectItems , setDateField ,
4
+ } from "../../shared/graphql_queries" ;
5
+ import { logger } from "../../shared/logger" ;
6
+ import { ALL_TEAMS_PROJECTS , NeonProject } from "../../shared/project_ids" ;
7
+ import { isDryRun } from "../../shared/utils" ;
8
+
9
+ const config : Array < Pick < NeonProject , 'projectId' | 'projectNumber' | 'updatedAtFieldId' | 'createdAtFieldId' | 'closedAtFieldId' > > = ALL_TEAMS_PROJECTS . map ( ( { projectId, projectNumber, updatedAtFieldId, createdAtFieldId, closedAtFieldId} ) => {
10
+ if ( ! projectId || ! projectNumber ) {
11
+ return ;
12
+ }
13
+
14
+ if ( ! createdAtFieldId && ! updatedAtFieldId && ! closedAtFieldId ) {
15
+ return ;
16
+ }
17
+
18
+ return {
19
+ projectNumber,
20
+ projectId,
21
+ createdAtFieldId,
22
+ updatedAtFieldId,
23
+ closedAtFieldId,
24
+ }
25
+ } ) . filter ( pr => Boolean ( pr ) ) as Array < Pick < NeonProject , 'projectId' | 'projectNumber' | 'updatedAtFieldId' | 'createdAtFieldId' | 'closedAtFieldId' > > ;
26
+ console . log ( config )
27
+
28
+ export const backfill_created_updated_deleted = async ( octokit : ProbotOctokit ) => {
29
+ console . time ( 'backfill_created_updated_deleted' )
30
+ let graphqlCounter = 0 ;
31
+ let backfilledItems = 0 ;
32
+ for ( let project of config ) {
33
+ if ( ! project ) {
34
+ break ;
35
+ }
36
+ console . time ( 'backfill_created_updated_deleted' + project . projectNumber )
37
+ let pageInfo : {
38
+ hasNextPage : boolean ,
39
+ endCursor : string ,
40
+ } = {
41
+ hasNextPage : true ,
42
+ endCursor : '' ,
43
+ }
44
+ while ( pageInfo . hasNextPage ) {
45
+ try {
46
+ const res : {
47
+ search : {
48
+ pageInfo : {
49
+ endCursor : string ,
50
+ hasNextPage : boolean ,
51
+ startCursor : string ,
52
+ hasPreviousPage : boolean ,
53
+ }
54
+ issueCount : number ,
55
+ nodes : Array < {
56
+ number : number ,
57
+ title : string ,
58
+ createdAt : string ,
59
+ updatedAt : string ,
60
+ closedAt ?: string ,
61
+ repository : {
62
+ name : string ,
63
+ }
64
+ author : {
65
+ login : string ,
66
+ }
67
+ projectItems : {
68
+ nodes : Array < {
69
+ id : string ,
70
+ isArchived : boolean ,
71
+ type : 'ISSUE' ,
72
+ updatedAt : string ,
73
+ project : {
74
+ id : string
75
+ }
76
+ fieldValues : {
77
+ nodes : Array < {
78
+ field : {
79
+ id : string ,
80
+ name : string ,
81
+ }
82
+ date : string ;
83
+ } >
84
+ } ,
85
+ } >
86
+ }
87
+ } >
88
+ }
89
+ } = await octokit . graphql ( getProjectItems , {
90
+ q : `org:neondatabase project:neondatabase/${ project . projectNumber } is:closed` ,
91
+ cursor : pageInfo . endCursor ,
92
+ } ) ;
93
+ logger ( 'info' , `total count: ${ res . search . issueCount } ` ) ;
94
+ const { search } = res ;
95
+ graphqlCounter ++ ;
96
+ logger ( 'info' , `processing page from cursor ${ pageInfo . endCursor } , itemsCount: ${ search . nodes . length } ` ) ;
97
+
98
+
99
+ pageInfo . endCursor = search . pageInfo . endCursor
100
+ pageInfo . hasNextPage = search . pageInfo . hasNextPage
101
+ let i = 0 ;
102
+ for ( let issue of search . nodes ) {
103
+ let backfilled = false ;
104
+ i ++ ;
105
+ logger ( 'info' , `it. #${ i } Processing issue #${ issue . number } ${ issue . title } ` )
106
+ if ( ! issue . projectItems || ! issue . projectItems . nodes || ! issue . projectItems . nodes . length ) {
107
+ logger ( 'info' , `Skip Processing issue #${ issue . number } ${ issue . title } : Does not belong to the project ${ project . projectNumber } ` )
108
+ continue ;
109
+ }
110
+
111
+ const projectItem = issue . projectItems . nodes . find ( ( conn ) => ( conn . project . id === project . projectId ) ) ;
112
+
113
+ if ( ! projectItem ) {
114
+ logger ( 'info' , `Skip Processing issue #${ issue . number } ${ issue . title } : Does not belong to the project ${ project . projectNumber } ` )
115
+ continue ;
116
+ }
117
+
118
+ if ( projectItem . isArchived ) {
119
+ logger ( 'info' , `Skip Processing issue #${ issue . number } ${ issue . title } : Archived in project ${ project . projectNumber } ` )
120
+ continue ;
121
+ }
122
+
123
+ const createdAtFieldDesiredValue = issue . createdAt ;
124
+ const updatedAtFiedDesiredValue = ( new Date ( projectItem . updatedAt ) . getTime ( ) ) >= new Date ( issue . updatedAt ) . getTime ( ) ?
125
+ projectItem . updatedAt : issue . updatedAt ;
126
+ const closedAtFieldDesiredValue = issue . closedAt ;
127
+
128
+ // @ts -ignore
129
+ const dateFieldsValues = Object . fromEntries ( projectItem . fieldValues . nodes . map ( ( fieldValueObj ) => {
130
+ if ( fieldValueObj . field ) {
131
+ return [ fieldValueObj . field . id , fieldValueObj . date ] ;
132
+ }
133
+ return ;
134
+ } ) . filter ( Boolean ) ) ;
135
+
136
+ if ( project . createdAtFieldId && ! dateFieldsValues [ project . createdAtFieldId ] && createdAtFieldDesiredValue ) {
137
+ graphqlCounter ++ ;
138
+ backfilled = true ;
139
+ if ( ! isDryRun ( ) ) {
140
+ try {
141
+ await octokit . graphql ( setDateField , {
142
+ project_id : project . projectId ,
143
+ project_item_id : projectItem . id ,
144
+ date_field_id : project . createdAtFieldId ,
145
+ value : createdAtFieldDesiredValue
146
+ } )
147
+ } catch ( e ) {
148
+ logger ( 'error' , e )
149
+ }
150
+ }
151
+ logger ( 'info' , `Set created at for issue #${ issue . number } ${ issue . title } in project ${ project . projectId } with value ${ createdAtFieldDesiredValue } ` )
152
+ }
153
+
154
+ if ( project . updatedAtFieldId && ! dateFieldsValues [ project . updatedAtFieldId ] && updatedAtFiedDesiredValue ) {
155
+ graphqlCounter ++ ;
156
+ backfilled = true ;
157
+
158
+ if ( ! isDryRun ( ) ) {
159
+ try {
160
+ await octokit . graphql ( setDateField , {
161
+ project_id : project . projectId ,
162
+ project_item_id : projectItem . id ,
163
+ date_field_id : project . updatedAtFieldId ,
164
+ value : updatedAtFiedDesiredValue
165
+ } )
166
+ } catch ( e ) {
167
+ logger ( 'error' , e )
168
+ }
169
+ }
170
+ logger ( 'info' , `Set updated at for issue #${ issue . number } ${ issue . title } in project ${ project . projectId } with value ${ updatedAtFiedDesiredValue } ` )
171
+ }
172
+
173
+ if ( project . closedAtFieldId && ! dateFieldsValues [ project . closedAtFieldId ] && closedAtFieldDesiredValue ) {
174
+ graphqlCounter ++ ;
175
+ backfilled = true ;
176
+
177
+ if ( ! isDryRun ( ) ) {
178
+ try {
179
+ await octokit . graphql ( setDateField , {
180
+ project_id : project . projectId ,
181
+ project_item_id : projectItem . id ,
182
+ date_field_id : project . closedAtFieldId ,
183
+ value : closedAtFieldDesiredValue
184
+ } )
185
+ } catch ( e ) {
186
+ logger ( 'error' , e )
187
+ }
188
+ }
189
+ logger ( 'info' , `Set updated at for issue #${ issue . number } ${ issue . title } in project ${ project . projectId } with value ${ closedAtFieldDesiredValue } ` )
190
+ }
191
+ if ( backfilled ) {
192
+ backfilledItems ++
193
+ }
194
+ logger ( 'info' , `Done processing issue #${ issue . number } ${ issue . title } ` )
195
+ }
196
+
197
+ logger ( 'info' , search ) ;
198
+ } catch ( e ) {
199
+ logger ( 'error' , e )
200
+ }
201
+
202
+ }
203
+ console . log ( `Backfilled ${ backfilledItems } items for project ${ project . projectNumber } , GraphQL requests count: ${ graphqlCounter } ` )
204
+ console . timeLog ( 'backfill_created_updated_deleted' , {
205
+ projectNumber : project . projectNumber
206
+ } )
207
+ console . timeEnd ( 'backfill_created_updated_deleted' + project . projectNumber )
208
+ }
209
+
210
+ console . timeEnd ( 'backfill_created_updated_deleted' )
211
+ }
0 commit comments