1+ use crate :: test_record;
12use anyhow:: Context ;
23use async_trait:: async_trait;
4+ use bytes:: Bytes ;
35use chrono:: { DateTime , FixedOffset , Utc } ;
46use futures:: { future:: BoxFuture , FutureExt } ;
57use hyper:: header:: HeaderValue ;
@@ -21,22 +23,32 @@ pub struct User {
2123}
2224
2325impl GithubClient {
24- async fn _send_req ( & self , req : RequestBuilder ) -> anyhow:: Result < ( Response , String ) > {
26+ async fn send_req ( & self , req : RequestBuilder ) -> anyhow:: Result < ( Bytes , String ) > {
2527 const MAX_ATTEMPTS : usize = 2 ;
26- log:: debug!( "_send_req with {:?}" , req) ;
28+ log:: debug!( "send_req with {:?}" , req) ;
2729 let req_dbg = format ! ( "{:?}" , req) ;
2830 let req = req
2931 . build ( )
3032 . with_context ( || format ! ( "building reqwest {}" , req_dbg) ) ?;
3133
34+ let test_capture_info = test_record:: capture_request ( & req) ;
35+
3236 let mut resp = self . client . execute ( req. try_clone ( ) . unwrap ( ) ) . await ?;
3337 if let Some ( sleep) = Self :: needs_retry ( & resp) . await {
3438 resp = self . retry ( req, sleep, MAX_ATTEMPTS ) . await ?;
3539 }
40+ let status = resp. status ( ) ;
41+ let maybe_err = resp. error_for_status_ref ( ) . err ( ) ;
42+ let body = resp
43+ . bytes ( )
44+ . await
45+ . with_context ( || format ! ( "failed to read response body {req_dbg}" ) ) ?;
46+ test_record:: record_request ( test_capture_info, status, & body) ;
47+ if let Some ( e) = maybe_err {
48+ return Err ( e. into ( ) ) ;
49+ }
3650
37- resp. error_for_status_ref ( ) ?;
38-
39- Ok ( ( resp, req_dbg) )
51+ Ok ( ( body, req_dbg) )
4052 }
4153
4254 async fn needs_retry ( resp : & Response ) -> Option < Duration > {
@@ -116,6 +128,7 @@ impl GithubClient {
116128 . unwrap ( ) ,
117129 )
118130 . await ?;
131+ rate_resp. error_for_status_ref ( ) ?;
119132 let rate_limit_response = rate_resp. json :: < RateLimitResponse > ( ) . await ?;
120133
121134 // Check url for search path because github has different rate limits for the search api
@@ -151,27 +164,12 @@ impl GithubClient {
151164 . boxed ( )
152165 }
153166
154- async fn send_req ( & self , req : RequestBuilder ) -> anyhow:: Result < Vec < u8 > > {
155- let ( mut resp, req_dbg) = self . _send_req ( req) . await ?;
156-
157- let mut body = Vec :: new ( ) ;
158- while let Some ( chunk) = resp. chunk ( ) . await . transpose ( ) {
159- let chunk = chunk
160- . context ( "reading stream failed" )
161- . map_err ( anyhow:: Error :: from)
162- . context ( req_dbg. clone ( ) ) ?;
163- body. extend_from_slice ( & chunk) ;
164- }
165-
166- Ok ( body)
167- }
168-
169167 pub async fn json < T > ( & self , req : RequestBuilder ) -> anyhow:: Result < T >
170168 where
171169 T : serde:: de:: DeserializeOwned ,
172170 {
173- let ( resp , req_dbg ) = self . _send_req ( req) . await ?;
174- Ok ( resp . json ( ) . await . context ( req_dbg ) ?)
171+ let ( body , _req_dbg ) = self . send_req ( req) . await ?;
172+ Ok ( serde_json :: from_slice ( & body ) ?)
175173 }
176174}
177175
@@ -414,8 +412,8 @@ impl IssueRepository {
414412 async fn has_label ( & self , client : & GithubClient , label : & str ) -> anyhow:: Result < bool > {
415413 #[ allow( clippy:: redundant_pattern_matching) ]
416414 let url = format ! ( "{}/labels/{}" , self . url( client) , label) ;
417- match client. _send_req ( client. get ( & url) ) . await {
418- Ok ( ( _ , _ ) ) => Ok ( true ) ,
415+ match client. send_req ( client. get ( & url) ) . await {
416+ Ok ( _ ) => Ok ( true ) ,
419417 Err ( e) => {
420418 if e. downcast_ref :: < reqwest:: Error > ( )
421419 . map_or ( false , |e| e. status ( ) == Some ( StatusCode :: NOT_FOUND ) )
@@ -495,7 +493,7 @@ impl Issue {
495493 body : & ' a str ,
496494 }
497495 client
498- . _send_req ( client. patch ( & edit_url) . json ( & ChangedIssue { body } ) )
496+ . send_req ( client. patch ( & edit_url) . json ( & ChangedIssue { body } ) )
499497 . await
500498 . context ( "failed to edit issue body" ) ?;
501499 Ok ( ( ) )
@@ -513,7 +511,7 @@ impl Issue {
513511 body : & ' a str ,
514512 }
515513 client
516- . _send_req (
514+ . send_req (
517515 client
518516 . patch ( & comment_url)
519517 . json ( & NewComment { body : new_body } ) ,
@@ -534,7 +532,7 @@ impl Issue {
534532 . expect ( "expected api host" ) ;
535533 let comments_url = format ! ( "{}{comments_path}" , client. api_url) ;
536534 client
537- . _send_req ( client. post ( & comments_url) . json ( & PostComment { body } ) )
535+ . send_req ( client. post ( & comments_url) . json ( & PostComment { body } ) )
538536 . await
539537 . context ( "failed to post comment" ) ?;
540538 Ok ( ( ) )
@@ -560,7 +558,7 @@ impl Issue {
560558 }
561559
562560 client
563- . _send_req ( client. delete ( & url) )
561+ . send_req ( client. delete ( & url) )
564562 . await
565563 . context ( "failed to delete label" ) ?;
566564
@@ -617,7 +615,7 @@ impl Issue {
617615 }
618616
619617 client
620- . _send_req ( client. post ( & url) . json ( & LabelsReq {
618+ . send_req ( client. post ( & url) . json ( & LabelsReq {
621619 labels : known_labels,
622620 } ) )
623621 . await
@@ -668,7 +666,7 @@ impl Issue {
668666 assignees : & ' a [ & ' a str ] ,
669667 }
670668 client
671- . _send_req ( client. delete ( & url) . json ( & AssigneeReq {
669+ . send_req ( client. delete ( & url) . json ( & AssigneeReq {
672670 assignees : & assignees[ ..] ,
673671 } ) )
674672 . await
@@ -761,7 +759,7 @@ impl Issue {
761759 }
762760 let url = format ! ( "{}/issues/{}" , self . repository( ) . url( client) , self . number) ;
763761 client
764- . _send_req ( client. patch ( & url) . json ( & SetMilestone {
762+ . send_req ( client. patch ( & url) . json ( & SetMilestone {
765763 milestone : milestone_no,
766764 } ) )
767765 . await
@@ -776,7 +774,7 @@ impl Issue {
776774 state : & ' a str ,
777775 }
778776 client
779- . _send_req (
777+ . send_req (
780778 client
781779 . patch ( & edit_url)
782780 . json ( & CloseIssue { state : "closed" } ) ,
@@ -801,8 +799,9 @@ impl Issue {
801799 after
802800 ) ) ;
803801 req = req. header ( "Accept" , "application/vnd.github.v3.diff" ) ;
804- let diff = client. send_req ( req) . await ?;
805- Ok ( Some ( String :: from ( String :: from_utf8_lossy ( & diff) ) ) )
802+ let ( diff, _) = client. send_req ( req) . await ?;
803+ let body = String :: from_utf8_lossy ( & diff) . to_string ( ) ;
804+ Ok ( Some ( body) )
806805 }
807806
808807 /// Returns the commits from this pull request (no commits are returned if this `Issue` is not
@@ -1246,7 +1245,7 @@ impl Repository {
12461245 ) -> anyhow:: Result < ( ) > {
12471246 let url = format ! ( "{}/git/refs/{}" , self . url( client) , refname) ;
12481247 client
1249- . _send_req ( client. patch ( & url) . json ( & serde_json:: json!( {
1248+ . send_req ( client. patch ( & url) . json ( & serde_json:: json!( {
12501249 "sha" : sha,
12511250 "force" : true ,
12521251 } ) ) )
@@ -1505,7 +1504,7 @@ impl Repository {
15051504 pub async fn merge_upstream ( & self , client : & GithubClient , branch : & str ) -> anyhow:: Result < ( ) > {
15061505 let url = format ! ( "{}/merge-upstream" , self . url( client) ) ;
15071506 client
1508- . _send_req ( client. post ( & url) . json ( & serde_json:: json!( {
1507+ . send_req ( client. post ( & url) . json ( & serde_json:: json!( {
15091508 "branch" : branch,
15101509 } ) ) )
15111510 . await
@@ -1811,27 +1810,23 @@ impl GithubClient {
18111810 repo : & str ,
18121811 branch : & str ,
18131812 path : & str ,
1814- ) -> anyhow:: Result < Option < Vec < u8 > > > {
1813+ ) -> anyhow:: Result < Option < Bytes > > {
18151814 let url = format ! ( "{}/{repo}/{branch}/{path}" , self . raw_url) ;
18161815 let req = self . get ( & url) ;
18171816 let req_dbg = format ! ( "{:?}" , req) ;
18181817 let req = req
18191818 . build ( )
18201819 . with_context ( || format ! ( "failed to build request {:?}" , req_dbg) ) ?;
1821- let mut resp = self . client . execute ( req) . await . context ( req_dbg. clone ( ) ) ?;
1820+ let test_capture_info = test_record:: capture_request ( & req) ;
1821+ let resp = self . client . execute ( req) . await . context ( req_dbg. clone ( ) ) ?;
18221822 let status = resp. status ( ) ;
1823+ let body = resp
1824+ . bytes ( )
1825+ . await
1826+ . with_context ( || format ! ( "failed to read response body {req_dbg}" ) ) ?;
1827+ test_record:: record_request ( test_capture_info, status, & body) ;
18231828 match status {
1824- StatusCode :: OK => {
1825- let mut buf = Vec :: with_capacity ( resp. content_length ( ) . unwrap_or ( 4 ) as usize ) ;
1826- while let Some ( chunk) = resp. chunk ( ) . await . transpose ( ) {
1827- let chunk = chunk
1828- . context ( "reading stream failed" )
1829- . map_err ( anyhow:: Error :: from)
1830- . context ( req_dbg. clone ( ) ) ?;
1831- buf. extend_from_slice ( & chunk) ;
1832- }
1833- Ok ( Some ( buf) )
1834- }
1829+ StatusCode :: OK => Ok ( Some ( body) ) ,
18351830 StatusCode :: NOT_FOUND => Ok ( None ) ,
18361831 status => anyhow:: bail!( "failed to GET {}: {}" , url, status) ,
18371832 }
@@ -2036,11 +2031,8 @@ impl IssuesQuery for LeastRecentlyReviewedPullRequests {
20362031 let req = client. post ( & format ! ( "{}/graphql" , client. api_url) ) ;
20372032 let req = req. json ( & query) ;
20382033
2039- let ( resp, req_dbg) = client. _send_req ( req) . await ?;
2040- let data = resp
2041- . json :: < cynic:: GraphQlResponse < queries:: LeastRecentlyReviewedPullRequests > > ( )
2042- . await
2043- . context ( req_dbg) ?;
2034+ let data: cynic:: GraphQlResponse < queries:: LeastRecentlyReviewedPullRequests > =
2035+ client. json ( req) . await ?;
20442036 if let Some ( errors) = data. errors {
20452037 anyhow:: bail!( "There were graphql errors. {:?}" , errors) ;
20462038 }
0 commit comments