11use std:: { sync:: Arc , time:: Duration } ;
22
3- use anyhow:: { bail, Context , Result } ;
3+ use anyhow:: { bail, Result } ;
44use chrono:: Utc ;
55use graphql_client:: { GraphQLQuery , QueryBody , Response as GraphQlResponse } ;
66use reqwest:: { Client , RequestBuilder , Response } ;
7- use serde:: Serialize ;
7+ use serde:: { Deserialize , Serialize } ;
88use tokio:: time;
99use tracing:: error;
1010
11+ use crate :: github:: issues:: {
12+ IssuesRepositoryIssuesNodesAuthor :: User as IssueAuthor ,
13+ IssuesRepositoryIssuesNodesCommentsNodesAuthor :: User as IssueCommentsAuthor ,
14+ IssuesRepositoryIssuesNodesProjectItemsNodesTodoInitiationOption as TodoInitOption ,
15+ IssuesRepositoryIssuesNodesProjectItemsNodesTodoPendingDays as TodoPendingDays ,
16+ IssuesRepositoryIssuesNodesProjectItemsNodesTodoPriority as TodoPriority ,
17+ IssuesRepositoryIssuesNodesProjectItemsNodesTodoSize as TodoSize ,
18+ IssuesRepositoryIssuesNodesProjectItemsNodesTodoStatus as TodoStatus ,
19+ IssuesRepositoryIssuesNodesSubIssuesNodesAuthor :: User as SubIssueAuthor ,
20+ IssuesRepositoryIssuesNodesClosedByPullRequestsReferencesEdgesNodeAuthor :: User as PullRequestRefAuthor ,
21+ } ;
22+ use crate :: graphql:: issue:: { Comment , SubIssue , ParentIssue , ProjectV2Item , ProjectV2ItemConnection , PullRequestRef } ;
1123use crate :: { database:: Database , github:: {
12- issues:: IssuesRepositoryIssuesNodesAuthor :: User as userName,
1324 pull_requests:: PullRequestsRepositoryPullRequestsNodesReviewRequestsNodesRequestedReviewer :: User ,
1425} , settings:: Repository as RepoInfo } ;
26+ pub ( crate ) use issues:: IssueState ;
27+ pub ( crate ) use issues:: PullRequestState ;
1528
1629const GITHUB_FETCH_SIZE : i64 = 10 ;
1730const GITHUB_URL : & str = "https://api.github.com/graphql" ;
1831const APP_USER_AGENT : & str = concat ! ( env!( "CARGO_PKG_NAME" ) , "/" , env!( "CARGO_PKG_VERSION" ) , ) ;
1932const INIT_TIME : & str = "1992-06-05T00:00:00Z" ;
2033
2134type DateTime = String ;
35+ #[ allow( clippy:: upper_case_acronyms) ]
36+ type URI = String ;
2237
2338#[ derive( GraphQLQuery ) ]
2439#[ graphql(
@@ -35,12 +50,25 @@ struct Issues;
3550) ]
3651struct PullRequests ;
3752
38- #[ derive( Debug ) ]
53+ #[ derive( Debug , Serialize , Deserialize ) ]
3954pub ( super ) struct GitHubIssue {
55+ pub ( super ) id : String ,
4056 pub ( super ) number : i64 ,
4157 pub ( super ) title : String ,
4258 pub ( super ) author : String ,
43- pub ( super ) closed_at : Option < DateTime > ,
59+ pub ( super ) body : String ,
60+ pub ( super ) state : IssueState ,
61+ pub ( super ) assignees : Vec < String > ,
62+ pub ( super ) labels : Vec < String > ,
63+ pub ( super ) comments : Vec < Comment > ,
64+ pub ( super ) project_items : ProjectV2ItemConnection ,
65+ pub ( super ) sub_issues : Vec < SubIssue > ,
66+ pub ( super ) parent : Option < ParentIssue > ,
67+ pub ( super ) url : String ,
68+ pub ( super ) closed_by_pull_requests : Vec < PullRequestRef > ,
69+ pub ( super ) created_at : String ,
70+ pub ( super ) updated_at : String ,
71+ pub ( super ) closed_at : Option < String > ,
4472}
4573
4674#[ derive( Debug ) ]
@@ -116,6 +144,7 @@ pub(super) async fn fetch_periodically(
116144 }
117145}
118146
147+ #[ allow( clippy:: too_many_lines) ]
119148async fn send_github_issue_query (
120149 owner : & str ,
121150 name : & str ,
@@ -132,38 +161,182 @@ async fn send_github_issue_query(
132161 first : Some ( GITHUB_FETCH_SIZE ) ,
133162 last : None ,
134163 before : None ,
135- after : end_cur,
164+ after : end_cur. take ( ) ,
136165 since : Some ( since. to_string ( ) ) ,
137166 } ;
138167 let resp_body: GraphQlResponse < issues:: ResponseData > =
139168 send_query :: < Issues > ( token, var) . await ?. json ( ) . await ?;
140169 if let Some ( data) = resp_body. data {
141170 if let Some ( repository) = data. repository {
142- if let Some ( nodes) = repository. issues . nodes . as_ref ( ) {
143- for issue in nodes. iter ( ) . flatten ( ) {
144- let mut author: String = String :: new ( ) ;
171+ let nodes = repository. issues . nodes . unwrap_or_default ( ) ;
172+ for issue in nodes. into_iter ( ) . flatten ( ) {
173+ let author = match issue. author {
174+ Some ( IssueAuthor ( u) ) => u. login ,
175+ _ => String :: new ( ) ,
176+ } ;
145177
146- let author_ref = issue. author . as_ref ( ) . context ( "Missing issue author" ) ?;
147- if let userName( on_user) = author_ref {
148- author. clone_from ( & on_user. login . clone ( ) ) ;
149- }
150- issues. push ( GitHubIssue {
151- number : issue. number ,
152- title : issue. title . to_string ( ) ,
153- author,
154- closed_at : issue. closed_at . clone ( ) ,
155- } ) ;
156- }
157- if !repository. issues . page_info . has_next_page {
158- total_issue. push ( issues) ;
159- break ;
160- }
161- end_cur = repository. issues . page_info . end_cursor ;
162- continue ;
178+ issues. push ( GitHubIssue {
179+ id : issue. id ,
180+ number : issue. number ,
181+ title : issue. title ,
182+ author,
183+ body : issue. body ,
184+ state : issue. state ,
185+ assignees : issue
186+ . assignees
187+ . nodes
188+ . unwrap_or_default ( )
189+ . into_iter ( )
190+ . flatten ( )
191+ . map ( |n| n. login )
192+ . collect ( ) ,
193+ labels : issue
194+ . labels
195+ . and_then ( |l| l. nodes )
196+ . unwrap_or_default ( )
197+ . into_iter ( )
198+ . flatten ( )
199+ . map ( |node| node. name )
200+ . collect ( ) ,
201+ comments : issue
202+ . comments
203+ . nodes
204+ . unwrap_or_default ( )
205+ . into_iter ( )
206+ . flatten ( )
207+ . map ( |comment| Comment {
208+ author : match comment. author {
209+ Some ( IssueCommentsAuthor ( u) ) => u. login ,
210+ _ => String :: new ( ) ,
211+ } ,
212+ body : comment. body ,
213+ created_at : comment. created_at ,
214+ id : comment. id ,
215+ repository_name : comment. repository . name ,
216+ updated_at : comment. updated_at ,
217+ url : comment. url ,
218+ } )
219+ . collect ( ) ,
220+ project_items : ProjectV2ItemConnection {
221+ total_count : issue. project_items . total_count ,
222+ nodes : issue
223+ . project_items
224+ . nodes
225+ . unwrap_or_default ( )
226+ . into_iter ( )
227+ . flatten ( )
228+ . map ( |node| ProjectV2Item {
229+ id : node. id ,
230+ todo_status : node. todo_status . and_then ( |status| match status {
231+ TodoStatus :: ProjectV2ItemFieldSingleSelectValue ( inner) => {
232+ inner. name
233+ }
234+ _ => None ,
235+ } ) ,
236+ todo_priority : node. todo_priority . and_then ( |priority| {
237+ match priority {
238+ TodoPriority :: ProjectV2ItemFieldSingleSelectValue (
239+ inner,
240+ ) => inner. name ,
241+ _ => None ,
242+ }
243+ } ) ,
244+ todo_size : node. todo_size . and_then ( |size| match size {
245+ TodoSize :: ProjectV2ItemFieldSingleSelectValue ( inner) => {
246+ inner. name
247+ }
248+ _ => None ,
249+ } ) ,
250+ todo_initiation_option : node. todo_initiation_option . and_then (
251+ |init| match init {
252+ TodoInitOption :: ProjectV2ItemFieldSingleSelectValue (
253+ inner,
254+ ) => inner. name ,
255+ _ => None ,
256+ } ,
257+ ) ,
258+ todo_pending_days : node. todo_pending_days . and_then ( |days| {
259+ match days {
260+ TodoPendingDays :: ProjectV2ItemFieldNumberValue (
261+ inner,
262+ ) => inner. number ,
263+ _ => None ,
264+ }
265+ } ) ,
266+ } )
267+ . collect ( ) ,
268+ } ,
269+
270+ sub_issues : issue
271+ . sub_issues
272+ . nodes
273+ . into_iter ( )
274+ . flatten ( )
275+ . flatten ( )
276+ . map ( |si| SubIssue {
277+ id : si. id ,
278+ number : si. number ,
279+ title : si. title ,
280+ state : si. state ,
281+ closed_at : si. closed_at ,
282+ created_at : si. created_at ,
283+ updated_at : si. updated_at ,
284+ author : match si. author {
285+ Some ( SubIssueAuthor ( u) ) => u. login ,
286+ _ => String :: new ( ) ,
287+ } ,
288+ assignees : si
289+ . assignees
290+ . nodes
291+ . into_iter ( )
292+ . flatten ( )
293+ . flatten ( )
294+ . map ( |n| n. login )
295+ . collect ( ) ,
296+ } )
297+ . collect ( ) ,
298+ parent : issue. parent . map ( |parent| ParentIssue {
299+ id : parent. id ,
300+ number : parent. number ,
301+ title : parent. title ,
302+ } ) ,
303+ url : issue. url ,
304+ closed_by_pull_requests : issue
305+ . closed_by_pull_requests_references
306+ . map ( |r| r. edges )
307+ . unwrap_or_default ( )
308+ . into_iter ( )
309+ . flatten ( )
310+ . flatten ( )
311+ . filter_map ( |edge| {
312+ edge. node . map ( |node| PullRequestRef {
313+ number : node. number ,
314+ state : node. state ,
315+ closed_at : node. closed_at ,
316+ created_at : node. created_at ,
317+ updated_at : node. updated_at ,
318+ author : match node. author {
319+ Some ( PullRequestRefAuthor ( u) ) => u. login ,
320+ _ => String :: new ( ) ,
321+ } ,
322+ url : node. url ,
323+ } )
324+ } )
325+ . collect ( ) ,
326+ created_at : issue. created_at ,
327+ updated_at : issue. updated_at ,
328+ closed_at : issue. closed_at ,
329+ } ) ;
163330 }
331+ if !repository. issues . page_info . has_next_page {
332+ total_issue. push ( issues) ;
333+ break ;
334+ }
335+ end_cur = repository. issues . page_info . end_cursor ;
336+ continue ;
164337 }
338+ bail ! ( "Failed to parse response data" ) ;
165339 }
166- bail ! ( "Failed to parse response data" ) ;
167340 }
168341 Ok ( total_issue)
169342}
0 commit comments