@@ -37,24 +37,31 @@ impl Generator {
3737
3838 self . fcps ( String :: from ( "T-libs-api" ) ) ?;
3939
40- IssueQuery :: new ( "Nominated" )
40+ GithubQuery :: new ( "Nominated" )
4141 . labels ( & [ "T-libs-api" , "I-nominated" ] )
4242 . repo ( "rust-lang/libs-team" )
4343 . repo ( "rust-lang/rust" )
4444 . repo ( "rust-lang/rfcs" )
4545 . write ( & mut self ) ?;
4646
47- IssueQuery :: new ( "Waiting on team" )
47+ GithubQuery :: new ( "Waiting on team" )
4848 . labels ( & [ "T-libs-api" , "S-waiting-on-team" ] )
4949 . repo ( "rust-lang/rust" )
5050 . repo ( "rust-lang/rfcs" )
5151 . write ( & mut self ) ?;
5252
53- IssueQuery :: new ( "Needs decision" )
53+ GithubQuery :: new ( "Needs decision" )
5454 . labels ( & [ "T-libs-api" , "I-needs-decision" ] )
5555 . repo ( "rust-lang/rust" )
5656 . write ( & mut self ) ?;
5757
58+ GithubQuery :: new ( "Stalled Tracking Issues" )
59+ . labels ( & [ "T-libs-api" , "C-tracking-issue" ] )
60+ . repo ( "rust-lang/rust" )
61+ . sort ( Sort :: LeastRecentlyUpdated )
62+ . take ( 5 )
63+ . write ( & mut self ) ?;
64+
5865 writeln ! ( & mut self . agenda,
5966 "## Actions
6067
@@ -91,41 +98,38 @@ impl Generator {
9198
9299 self . fcps ( String :: from ( "T-libs" ) ) ?;
93100
94- IssueQuery :: new ( "Critical" )
101+ GithubQuery :: new ( "Critical" )
95102 . labels ( & [ "T-libs" , "P-critical" ] )
96103 . labels ( & [ "T-libs-api" , "P-critical" ] )
97104 . repo ( "rust-lang/rust" )
98105 . repo ( "rust-lang/rfcs" )
99106 . write ( & mut self ) ?;
100107
101- IssueQuery :: new ( "Prioritization Requested" )
108+ GithubQuery :: new ( "Prioritization Requested" )
102109 . labels ( & [ "T-libs" , "I-prioritize" ] )
103110 . labels ( & [ "T-libs-api" , "I-prioritize" ] )
104111 . repo ( "rust-lang/rust" )
105112 . repo ( "rust-lang/rfcs" )
106113 . write ( & mut self ) ?;
107114
108- IssueQuery :: new ( "Nominated" )
115+ GithubQuery :: new ( "Nominated" )
109116 . labels ( & [ "T-libs" , "I-nominated" ] )
110117 . repo ( "rust-lang/rust" )
111118 . repo ( "rust-lang/rfcs" )
112119 . repo ( "rust-lang/libs-team" )
113120 . write ( & mut self ) ?;
114121
115- IssueQuery :: new ( "Backports" )
122+ GithubQuery :: new ( "Backports" )
116123 . labels ( & [ "T-libs" , "stable-nominated" ] )
117124 . labels ( & [ "T-libs-api" , "stable-nominated" ] )
118- . labels ( & [ "T-libs" , "stable-accepted" ] )
119- . labels ( & [ "T-libs-api" , "stable-accepted" ] )
120125 . labels ( & [ "T-libs" , "beta-nominated" ] )
121126 . labels ( & [ "T-libs-api" , "beta-nominated" ] )
122- . labels ( & [ "T-libs" , "beta-accepted" ] )
123- . labels ( & [ "T-libs-api" , "beta-accepted" ] )
127+ . state ( State :: Any )
124128 . repo ( "rust-lang/rust" )
125129 . repo ( "rust-lang/rfcs" )
126130 . write ( & mut self ) ?;
127131
128- IssueQuery :: new ( "Regressions" )
132+ GithubQuery :: new ( "Regressions" )
129133 . labels ( & [ "T-libs" , "regression-untriaged" ] )
130134 . labels ( & [ "T-libs-api" , "regression-untriaged" ] )
131135 . labels ( & [ "T-libs" , "regression-from-stable-to-stable" ] )
@@ -150,24 +154,24 @@ impl Generator {
150154 }
151155
152156 pub fn error_handling_pg_agenda ( mut self ) -> Result < String > {
153- IssueQuery :: new ( "Nominated" )
157+ GithubQuery :: new ( "Nominated" )
154158 . labels ( & [ "PG-error-handling" , "I-nominated" ] )
155159 . repo ( "rust-lang/rust" )
156160 . repo ( "rust-lang/project-error-handling" )
157161 . write ( & mut self ) ?;
158162
159- IssueQuery :: new ( "PG Error Handling" )
163+ GithubQuery :: new ( "PG Error Handling" )
160164 . labels ( & [ "PG-error-handling" ] )
161165 . repo ( "rust-lang/rust" )
162166 . repo ( "rust-lang/project-error-handling" )
163167 . write ( & mut self ) ?;
164168
165- IssueQuery :: new ( "Area Error Handling" )
169+ GithubQuery :: new ( "Area Error Handling" )
166170 . labels ( & [ "A-error-handling" ] )
167171 . repo ( "rust-lang/rust" )
168172 . write ( & mut self ) ?;
169173
170- IssueQuery :: new ( "PG Error Handling" )
174+ GithubQuery :: new ( "PG Error Handling" )
171175 . repo ( "rust-lang/project-error-handling" )
172176 . write ( & mut self ) ?;
173177
@@ -342,24 +346,89 @@ impl Generator {
342346 Ok ( ( ) )
343347 }
344348
345- fn dedup ( & mut self , mut issues : Vec < Issue > ) -> Vec < Issue > {
346- issues. retain ( |issue| self . seen . insert ( issue. html_url . clone ( ) ) ) ;
347- issues
349+ fn dedup ( & mut self , issues : Vec < Issue > ) -> impl Iterator < Item = Issue > + ' _ {
350+ issues. into_iter ( ) . filter ( move |issue| self . seen . insert ( issue. html_url . clone ( ) ) )
351+ }
352+ }
353+
354+ #[ derive( Clone , Copy ) ]
355+ #[ allow( dead_code) ]
356+ enum Sort {
357+ Newest ,
358+ Oldest ,
359+ MostCommented ,
360+ LeastCommented ,
361+ MostRecentlyUpdated ,
362+ LeastRecentlyUpdated ,
363+ }
364+
365+ impl Sort {
366+ fn api_str ( & self ) -> & ' static str {
367+ match self {
368+ Sort :: Newest => "&sort=created&direction=desc" ,
369+ Sort :: Oldest => "&sort=created&direction=asc" ,
370+ Sort :: MostCommented => "&sort=comments&direction=asc" ,
371+ Sort :: LeastCommented => "&sort=comments&direction=desc" ,
372+ Sort :: MostRecentlyUpdated => "&sort=updated&direction=desc" ,
373+ Sort :: LeastRecentlyUpdated => "&sort=updated&direction=asc" ,
374+ }
375+ }
376+
377+ fn web_ui_str ( & self ) -> & ' static str {
378+ match self {
379+ Sort :: Newest => "+sort:created-desc" ,
380+ Sort :: Oldest => "+sort:created-asc" ,
381+ Sort :: MostCommented => "+sort:comments-desc" ,
382+ Sort :: LeastCommented => "+sort:comments-asc" ,
383+ Sort :: MostRecentlyUpdated => "+sort:updated-desc" ,
384+ Sort :: LeastRecentlyUpdated => "+sort:updated-asc" ,
385+ }
348386 }
349387}
350388
351- struct IssueQuery {
389+ struct GithubQuery {
352390 name : & ' static str ,
353391 labels : Vec < & ' static [ & ' static str ] > ,
354392 repos : Vec < & ' static str > ,
393+ sort : Option < Sort > ,
394+ count : Option < usize > ,
395+ state : State ,
396+ }
397+
398+ #[ allow( dead_code) ]
399+ enum State {
400+ Open ,
401+ Closed ,
402+ Any ,
403+ }
404+
405+ impl State {
406+ fn api_str ( & self ) -> & ' static str {
407+ match self {
408+ State :: Open => "&state=open" ,
409+ State :: Closed => "&state=closed" ,
410+ State :: Any => "&state=all" ,
411+ }
412+ }
413+
414+ fn web_ui_str ( & self ) -> & ' static str {
415+ match self {
416+ State :: Open => "+is:open" ,
417+ State :: Closed => "+is:closed" ,
418+ State :: Any => "" ,
419+ }
420+ }
355421}
356422
357- impl IssueQuery {
423+ impl GithubQuery {
358424 fn new ( name : & ' static str ) -> Self {
359425 Self {
360426 name,
361427 labels : vec ! [ ] ,
362428 repos : vec ! [ ] ,
429+ sort : None ,
430+ count : None ,
431+ state : State :: Open ,
363432 }
364433 }
365434
@@ -373,6 +442,21 @@ impl IssueQuery {
373442 self
374443 }
375444
445+ fn sort ( & mut self , sort : Sort ) -> & mut Self {
446+ self . sort = Some ( sort) ;
447+ self
448+ }
449+
450+ fn take ( & mut self , count : usize ) -> & mut Self {
451+ self . count = Some ( count) ;
452+ self
453+ }
454+
455+ fn state ( & mut self , state : State ) -> & mut Self {
456+ self . state = state;
457+ self
458+ }
459+
376460 fn write ( & mut self , generator : & mut Generator ) -> Result < ( ) > {
377461 writeln ! ( generator. agenda, "### {}" , self . name) ?;
378462 writeln ! ( generator. agenda, ) ?;
@@ -382,8 +466,21 @@ impl IssueQuery {
382466 for repo in & self . repos {
383467 for labels in & self . labels {
384468 let cs_labels = labels. join ( "," ) ;
385- let endpoint = format ! ( "repos/{}/issues?labels={}" , repo, cs_labels) ;
386- let issues = generator. dedup ( github_api ( & endpoint) ?) ;
469+ let mut endpoint = format ! ( "repos/{}/issues?labels={}" , repo, cs_labels) ;
470+
471+ endpoint += self . state . api_str ( ) ;
472+
473+ if let Some ( sort) = self . sort {
474+ endpoint += sort. api_str ( ) ;
475+ }
476+
477+ let issues = github_api ( & endpoint) ?;
478+ let issues = generator. dedup ( issues) ;
479+ let issues: Vec < _ > = if let Some ( count) = self . count {
480+ issues. take ( count) . collect ( )
481+ } else {
482+ issues. collect ( )
483+ } ;
387484
388485 if issues. is_empty ( ) {
389486 continue ;
@@ -393,13 +490,23 @@ impl IssueQuery {
393490 . iter ( )
394491 . map ( |label| format ! ( "label:{}" , label) )
395492 . join ( "+" ) ;
493+
494+ let mut url = format ! ( "https://github.com/{}/issues?q={}" , repo, url_labels) ;
495+
496+ url += self . state . web_ui_str ( ) ;
497+
498+ if let Some ( sort) = self . sort {
499+ url += sort. web_ui_str ( ) ;
500+ }
501+
502+
396503 writeln ! (
397504 generator. agenda,
398- "- [{} `{repo}` `{labels}` items](https://github.com/{repo}/issues?q=is:open+{url_labels })" ,
505+ "- [{} `{repo}` `{labels}` items]({url })" ,
399506 issues. len( ) ,
400507 repo = repo,
401508 labels = labels. join( "` `" ) ,
402- url_labels = url_labels ,
509+ url = url ,
403510 ) ?;
404511 generator. write_issues ( & issues) ?;
405512
@@ -450,8 +557,9 @@ fn escape(v: &str) -> String {
450557}
451558
452559fn github_api < T : DeserializeOwned > ( endpoint : & str ) -> Result < T > {
560+ let url = format ! ( "https://api.github.com/{}" , endpoint) ;
453561 let mut client = reqwest:: blocking:: Client :: new ( )
454- . get ( & format ! ( "https://api.github.com/{}" , endpoint ) )
562+ . get ( & url )
455563 . header ( USER_AGENT , "rust-lang libs agenda maker" ) ;
456564 if let Ok ( token) = std:: env:: var ( "GITHUB_TOKEN" ) {
457565 client = client. header ( AUTHORIZATION , format ! ( "token {}" , token) ) ;
0 commit comments