@@ -5,6 +5,7 @@ use askama::Template;
55use chrono:: prelude:: * ;
66use chrono:: Duration ;
77
8+ use reqwest:: header:: HeaderMap ;
89use serde_json as json;
910
1011type JsonRefArray < ' a > = Vec < & ' a json:: Value > ;
@@ -54,9 +55,10 @@ fn main() {
5455 while today - end > six_weeks {
5556 end = end + six_weeks;
5657 }
57-
5858 let start = end - six_weeks;
59- let issues = get_issues ( start, end, "rust" ) ;
59+
60+ let mut issues = get_issues_by_milestone ( & version, "rust" ) ;
61+ issues. sort_by_cached_key ( |issue| issue[ "number" ] . as_u64 ( ) . unwrap ( ) ) ;
6062
6163 // Skips `beta-accepted` as those PRs were backported onto the
6264 // previous stable.
@@ -84,7 +86,8 @@ fn main() {
8486 let ( compat_unsorted, libraries_unsorted, language_unsorted, compiler_unsorted, unsorted) =
8587 partition_prs ( rest) ;
8688
87- let cargo_issues = get_issues ( start, end, "cargo" ) ;
89+ let mut cargo_issues = get_issues_by_date ( start, end, "cargo" ) ;
90+ cargo_issues. sort_by_cached_key ( |issue| issue[ "number" ] . as_u64 ( ) . unwrap ( ) ) ;
8891
8992 let ( cargo_relnotes, cargo_unsorted) = {
9093 let ( relnotes, rest) = partition_by_tag ( cargo_issues. iter ( ) , relnotes_tags) ;
@@ -119,21 +122,99 @@ fn main() {
119122 println ! ( "{}" , relnotes. render( ) . unwrap( ) ) ;
120123}
121124
122- fn get_issues ( start : Date < Utc > , end : Date < Utc > , repo_name : & ' static str ) -> Vec < json:: Value > {
125+ fn get_issues_by_milestone ( version : & str , repo_name : & ' static str ) -> Vec < json:: Value > {
123126 use reqwest:: blocking:: Client ;
124- use reqwest:: header:: * ;
125127
126- let token = env:: var ( "GITHUB_TOKEN" ) . expect ( "Set GITHUB_TOKEN to a valid token" ) ;
127- let mut headers = HeaderMap :: new ( ) ;
128- headers. insert ( CONTENT_TYPE , "application/json" . parse ( ) . unwrap ( ) ) ;
129- headers. insert ( ACCEPT , "application/json" . parse ( ) . unwrap ( ) ) ;
130- headers. insert (
131- AUTHORIZATION ,
132- format ! ( "Bearer {}" , token)
133- . parse ( )
134- . unwrap ( ) ,
135- ) ;
136- headers. insert ( USER_AGENT , "Rust-relnotes/0.1.0" . parse ( ) . unwrap ( ) ) ;
128+ let headers = request_header ( ) ;
129+ let mut args = BTreeMap :: new ( ) ;
130+ args. insert ( "states" , String :: from ( "[MERGED]" ) ) ;
131+ args. insert ( "last" , String :: from ( "100" ) ) ;
132+ let mut issues = Vec :: new ( ) ;
133+
134+ loop {
135+ let query = format ! (
136+ r#"
137+ query {{
138+ repository(owner: "rust-lang", name: "{repo_name}") {{
139+ milestones(query: "{version}", first: 1) {{
140+ totalCount
141+ nodes {{
142+ pullRequests({args}) {{
143+ nodes {{
144+ number
145+ title
146+ url
147+ labels(last: 100) {{
148+ nodes {{
149+ name
150+ }}
151+ }}
152+ }}
153+ pageInfo {{
154+ startCursor
155+ }}
156+ }}
157+ }}
158+ }}
159+ }}
160+ }}"# ,
161+ repo_name = repo_name,
162+ version = version,
163+ args = args
164+ . iter( )
165+ . map( |( k, v) | format!( "{}: {}" , k, v) )
166+ . collect:: <Vec <_>>( )
167+ . join( "," )
168+ )
169+ . replace ( " " , "" )
170+ . replace ( "\n " , " " )
171+ . replace ( '"' , "\\ \" " ) ;
172+
173+ let json_query = format ! ( "{{\" query\" : \" {}\" }}" , query) ;
174+
175+ let client = Client :: new ( ) ;
176+
177+ let json = client
178+ . post ( "https://api.github.com/graphql" )
179+ . headers ( headers. clone ( ) )
180+ . body ( json_query)
181+ . send ( )
182+ . unwrap ( )
183+ . json :: < json:: Value > ( )
184+ . unwrap ( ) ;
185+
186+ let milestones_data = json[ "data" ] [ "repository" ] [ "milestones" ] . clone ( ) ;
187+ assert_eq ! (
188+ milestones_data[ "totalCount" ] . as_u64( ) . unwrap( ) ,
189+ 1 ,
190+ "More than one milestone matched the query \" {version}\" . Please be more specific." ,
191+ version = version
192+ ) ;
193+ let pull_requests_data = milestones_data[ "nodes" ] [ 0 ] [ "pullRequests" ] . clone ( ) ;
194+
195+ let mut pull_requests = pull_requests_data[ "nodes" ] . as_array ( ) . unwrap ( ) . clone ( ) ;
196+ issues. append ( & mut pull_requests) ;
197+
198+ match & pull_requests_data[ "pageInfo" ] [ "startCursor" ] {
199+ json:: Value :: String ( cursor) => {
200+ args. insert ( "before" , format ! ( "\" {}\" " , cursor) ) ;
201+ }
202+ json:: Value :: Null => {
203+ break issues;
204+ }
205+ _ => unreachable ! ( ) ,
206+ }
207+ }
208+ }
209+
210+ fn get_issues_by_date (
211+ start : Date < Utc > ,
212+ end : Date < Utc > ,
213+ repo_name : & ' static str ,
214+ ) -> Vec < json:: Value > {
215+ use reqwest:: blocking:: Client ;
216+
217+ let headers = request_header ( ) ;
137218 let mut args = BTreeMap :: new ( ) ;
138219 args. insert ( "states" , String :: from ( "[MERGED]" ) ) ;
139220 args. insert ( "last" , String :: from ( "100" ) ) ;
@@ -142,9 +223,9 @@ fn get_issues(start: Date<Utc>, end: Date<Utc>, repo_name: &'static str) -> Vec<
142223
143224 loop {
144225 let query = format ! (
145- "
226+ r# "
146227 query {{
147- repository(owner: \ " rust-lang\ " , name: \ " {repo_name}\ " ) {{
228+ repository(owner: "rust-lang", name: "{repo_name}") {{
148229 pullRequests({args}) {{
149230 nodes {{
150231 mergedAt
@@ -162,7 +243,7 @@ fn get_issues(start: Date<Utc>, end: Date<Utc>, repo_name: &'static str) -> Vec<
162243 }}
163244 }}
164245 }}
165- }}" ,
246+ }}"# ,
166247 repo_name = repo_name,
167248 args = args
168249 . iter( )
@@ -229,6 +310,17 @@ fn get_issues(start: Date<Utc>, end: Date<Utc>, repo_name: &'static str) -> Vec<
229310 }
230311}
231312
313+ fn request_header ( ) -> HeaderMap {
314+ use reqwest:: header:: * ;
315+ let token = env:: var ( "GITHUB_TOKEN" ) . expect ( "Set GITHUB_TOKEN to a valid token" ) ;
316+ let mut headers = HeaderMap :: new ( ) ;
317+ headers. insert ( CONTENT_TYPE , "application/json" . parse ( ) . unwrap ( ) ) ;
318+ headers. insert ( ACCEPT , "application/json" . parse ( ) . unwrap ( ) ) ;
319+ headers. insert ( AUTHORIZATION , format ! ( "Bearer {}" , token) . parse ( ) . unwrap ( ) ) ;
320+ headers. insert ( USER_AGENT , "Rust-relnotes/0.1.0" . parse ( ) . unwrap ( ) ) ;
321+ headers
322+ }
323+
232324fn map_to_line_items < ' a > (
233325 prefix : & ' static str ,
234326 iter : impl IntoIterator < Item = & ' a json:: Value > ,
0 commit comments