1
1
use anyhow:: { anyhow, Context } ;
2
2
use async_trait:: async_trait;
3
+ use bytes:: Bytes ;
3
4
use chrono:: { DateTime , FixedOffset , Utc } ;
4
5
use futures:: { future:: BoxFuture , FutureExt } ;
5
6
use hyper:: header:: HeaderValue ;
@@ -21,9 +22,9 @@ pub struct User {
21
22
}
22
23
23
24
impl GithubClient {
24
- async fn _send_req ( & self , req : RequestBuilder ) -> anyhow:: Result < ( Response , String ) > {
25
+ async fn send_req ( & self , req : RequestBuilder ) -> anyhow:: Result < ( Bytes , String ) > {
25
26
const MAX_ATTEMPTS : usize = 2 ;
26
- log:: debug!( "_send_req with {:?}" , req) ;
27
+ log:: debug!( "send_req with {:?}" , req) ;
27
28
let req_dbg = format ! ( "{:?}" , req) ;
28
29
let req = req
29
30
. build ( )
@@ -33,10 +34,17 @@ impl GithubClient {
33
34
if let Some ( sleep) = Self :: needs_retry ( & resp) . await {
34
35
resp = self . retry ( req, sleep, MAX_ATTEMPTS ) . await ?;
35
36
}
37
+ let maybe_err = resp. error_for_status_ref ( ) . err ( ) ;
38
+ let body = resp
39
+ . bytes ( )
40
+ . await
41
+ . with_context ( || format ! ( "failed to read response body {req_dbg}" ) ) ?;
42
+ if let Some ( e) = maybe_err {
43
+ return Err ( anyhow:: Error :: new ( e) )
44
+ . with_context ( || format ! ( "response: {}" , String :: from_utf8_lossy( & body) ) ) ;
45
+ }
36
46
37
- resp. error_for_status_ref ( ) ?;
38
-
39
- Ok ( ( resp, req_dbg) )
47
+ Ok ( ( body, req_dbg) )
40
48
}
41
49
42
50
async fn needs_retry ( resp : & Response ) -> Option < Duration > {
@@ -151,27 +159,12 @@ impl GithubClient {
151
159
. boxed ( )
152
160
}
153
161
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
-
169
162
pub async fn json < T > ( & self , req : RequestBuilder ) -> anyhow:: Result < T >
170
163
where
171
164
T : serde:: de:: DeserializeOwned ,
172
165
{
173
- let ( resp , req_dbg ) = self . _send_req ( req) . await ?;
174
- Ok ( resp . json ( ) . await . context ( req_dbg ) ?)
166
+ let ( body , _req_dbg ) = self . send_req ( req) . await ?;
167
+ Ok ( serde_json :: from_slice ( & body ) ?)
175
168
}
176
169
}
177
170
@@ -412,8 +405,8 @@ impl IssueRepository {
412
405
async fn has_label ( & self , client : & GithubClient , label : & str ) -> anyhow:: Result < bool > {
413
406
#[ allow( clippy:: redundant_pattern_matching) ]
414
407
let url = format ! ( "{}/labels/{}" , self . url( ) , label) ;
415
- match client. _send_req ( client. get ( & url) ) . await {
416
- Ok ( ( _ , _ ) ) => Ok ( true ) ,
408
+ match client. send_req ( client. get ( & url) ) . await {
409
+ Ok ( _ ) => Ok ( true ) ,
417
410
Err ( e) => {
418
411
if e. downcast_ref :: < reqwest:: Error > ( )
419
412
. map_or ( false , |e| e. status ( ) == Some ( StatusCode :: NOT_FOUND ) )
@@ -493,7 +486,7 @@ impl Issue {
493
486
body : & ' a str ,
494
487
}
495
488
client
496
- . _send_req ( client. patch ( & edit_url) . json ( & ChangedIssue { body } ) )
489
+ . send_req ( client. patch ( & edit_url) . json ( & ChangedIssue { body } ) )
497
490
. await
498
491
. context ( "failed to edit issue body" ) ?;
499
492
Ok ( ( ) )
@@ -511,7 +504,7 @@ impl Issue {
511
504
body : & ' a str ,
512
505
}
513
506
client
514
- . _send_req (
507
+ . send_req (
515
508
client
516
509
. patch ( & comment_url)
517
510
. json ( & NewComment { body : new_body } ) ,
@@ -527,7 +520,7 @@ impl Issue {
527
520
body : & ' a str ,
528
521
}
529
522
client
530
- . _send_req ( client. post ( & self . comments_url ) . json ( & PostComment { body } ) )
523
+ . send_req ( client. post ( & self . comments_url ) . json ( & PostComment { body } ) )
531
524
. await
532
525
. context ( "failed to post comment" ) ?;
533
526
Ok ( ( ) )
@@ -553,7 +546,7 @@ impl Issue {
553
546
}
554
547
555
548
client
556
- . _send_req ( client. delete ( & url) )
549
+ . send_req ( client. delete ( & url) )
557
550
. await
558
551
. context ( "failed to delete label" ) ?;
559
552
@@ -610,7 +603,7 @@ impl Issue {
610
603
}
611
604
612
605
client
613
- . _send_req ( client. post ( & url) . json ( & LabelsReq {
606
+ . send_req ( client. post ( & url) . json ( & LabelsReq {
614
607
labels : known_labels,
615
608
} ) )
616
609
. await
@@ -661,7 +654,7 @@ impl Issue {
661
654
assignees : & ' a [ & ' a str ] ,
662
655
}
663
656
client
664
- . _send_req ( client. delete ( & url) . json ( & AssigneeReq {
657
+ . send_req ( client. delete ( & url) . json ( & AssigneeReq {
665
658
assignees : & assignees[ ..] ,
666
659
} ) )
667
660
. await
@@ -754,7 +747,7 @@ impl Issue {
754
747
}
755
748
let url = format ! ( "{}/issues/{}" , self . repository( ) . url( ) , self . number) ;
756
749
client
757
- . _send_req ( client. patch ( & url) . json ( & SetMilestone {
750
+ . send_req ( client. patch ( & url) . json ( & SetMilestone {
758
751
milestone : milestone_no,
759
752
} ) )
760
753
. await
@@ -769,7 +762,7 @@ impl Issue {
769
762
state : & ' a str ,
770
763
}
771
764
client
772
- . _send_req (
765
+ . send_req (
773
766
client
774
767
. patch ( & edit_url)
775
768
. json ( & CloseIssue { state : "closed" } ) ,
@@ -794,8 +787,9 @@ impl Issue {
794
787
after
795
788
) ) ;
796
789
req = req. header ( "Accept" , "application/vnd.github.v3.diff" ) ;
797
- let diff = client. send_req ( req) . await ?;
798
- Ok ( Some ( String :: from ( String :: from_utf8_lossy ( & diff) ) ) )
790
+ let ( diff, _) = client. send_req ( req) . await ?;
791
+ let body = String :: from_utf8_lossy ( & diff) . to_string ( ) ;
792
+ Ok ( Some ( body) )
799
793
}
800
794
801
795
/// Returns the commits from this pull request (no commits are returned if this `Issue` is not
@@ -1235,7 +1229,7 @@ impl Repository {
1235
1229
) -> anyhow:: Result < ( ) > {
1236
1230
let url = format ! ( "{}/git/refs/{}" , self . url( ) , refname) ;
1237
1231
client
1238
- . _send_req ( client. patch ( & url) . json ( & serde_json:: json!( {
1232
+ . json ( client. patch ( & url) . json ( & serde_json:: json!( {
1239
1233
"sha" : sha,
1240
1234
"force" : true ,
1241
1235
} ) ) )
@@ -1494,7 +1488,7 @@ impl Repository {
1494
1488
pub async fn merge_upstream ( & self , client : & GithubClient , branch : & str ) -> anyhow:: Result < ( ) > {
1495
1489
let url = format ! ( "{}/merge-upstream" , self . url( ) ) ;
1496
1490
client
1497
- . _send_req ( client. post ( & url) . json ( & serde_json:: json!( {
1491
+ . send_req ( client. post ( & url) . json ( & serde_json:: json!( {
1498
1492
"branch" : branch,
1499
1493
} ) ) )
1500
1494
. await
@@ -1783,7 +1777,7 @@ impl GithubClient {
1783
1777
repo : & str ,
1784
1778
branch : & str ,
1785
1779
path : & str ,
1786
- ) -> anyhow:: Result < Option < Vec < u8 > > > {
1780
+ ) -> anyhow:: Result < Option < Bytes > > {
1787
1781
let url = format ! (
1788
1782
"https://raw.githubusercontent.com/{}/{}/{}" ,
1789
1783
repo, branch, path
@@ -1793,20 +1787,14 @@ impl GithubClient {
1793
1787
let req = req
1794
1788
. build ( )
1795
1789
. with_context ( || format ! ( "failed to build request {:?}" , req_dbg) ) ?;
1796
- let mut resp = self . client . execute ( req) . await . context ( req_dbg. clone ( ) ) ?;
1790
+ let resp = self . client . execute ( req) . await . context ( req_dbg. clone ( ) ) ?;
1797
1791
let status = resp. status ( ) ;
1792
+ let body = resp
1793
+ . bytes ( )
1794
+ . await
1795
+ . with_context ( || format ! ( "failed to read response body {req_dbg}" ) ) ?;
1798
1796
match status {
1799
- StatusCode :: OK => {
1800
- let mut buf = Vec :: with_capacity ( resp. content_length ( ) . unwrap_or ( 4 ) as usize ) ;
1801
- while let Some ( chunk) = resp. chunk ( ) . await . transpose ( ) {
1802
- let chunk = chunk
1803
- . context ( "reading stream failed" )
1804
- . map_err ( anyhow:: Error :: from)
1805
- . context ( req_dbg. clone ( ) ) ?;
1806
- buf. extend_from_slice ( & chunk) ;
1807
- }
1808
- Ok ( Some ( buf) )
1809
- }
1797
+ StatusCode :: OK => Ok ( Some ( body) ) ,
1810
1798
StatusCode :: NOT_FOUND => Ok ( None ) ,
1811
1799
status => anyhow:: bail!( "failed to GET {}: {}" , url, status) ,
1812
1800
}
@@ -2010,11 +1998,8 @@ impl IssuesQuery for LeastRecentlyReviewedPullRequests {
2010
1998
let req = client. post ( Repository :: GITHUB_GRAPHQL_API_URL ) ;
2011
1999
let req = req. json ( & query) ;
2012
2000
2013
- let ( resp, req_dbg) = client. _send_req ( req) . await ?;
2014
- let data = resp
2015
- . json :: < cynic:: GraphQlResponse < queries:: LeastRecentlyReviewedPullRequests > > ( )
2016
- . await
2017
- . context ( req_dbg) ?;
2001
+ let data: cynic:: GraphQlResponse < queries:: LeastRecentlyReviewedPullRequests > =
2002
+ client. json ( req) . await ?;
2018
2003
if let Some ( errors) = data. errors {
2019
2004
anyhow:: bail!( "There were graphql errors. {:?}" , errors) ;
2020
2005
}
@@ -2147,11 +2132,7 @@ async fn project_items_by_status(
2147
2132
let req = client. post ( Repository :: GITHUB_GRAPHQL_API_URL ) ;
2148
2133
let req = req. json ( & query) ;
2149
2134
2150
- let ( resp, req_dbg) = client. _send_req ( req) . await ?;
2151
- let data = resp
2152
- . json :: < cynic:: GraphQlResponse < project_items_by_status:: Query > > ( )
2153
- . await
2154
- . context ( req_dbg) ?;
2135
+ let data: cynic:: GraphQlResponse < project_items_by_status:: Query > = client. json ( req) . await ?;
2155
2136
if let Some ( errors) = data. errors {
2156
2137
anyhow:: bail!( "There were graphql errors. {:?}" , errors) ;
2157
2138
}
0 commit comments