@@ -192,20 +192,40 @@ impl RestApiClient for GithubApiClient {
192
192
. unwrap ( ) ;
193
193
let mut diff_header = HeaderMap :: new ( ) ;
194
194
diff_header. insert ( "Accept" , "application/vnd.github.diff" . parse ( ) . unwrap ( ) ) ;
195
- let request =
196
- Self :: make_api_request ( & self . client , url, Method :: GET , None , Some ( diff_header) ) ;
195
+ let request = Self :: make_api_request (
196
+ & self . client ,
197
+ url. as_str ( ) ,
198
+ Method :: GET ,
199
+ None ,
200
+ Some ( diff_header) ,
201
+ ) ;
197
202
let response = Self :: send_api_request (
198
203
self . client . clone ( ) ,
199
204
request,
200
- true ,
205
+ false ,
201
206
self . rate_limit_headers . to_owned ( ) ,
202
207
0 ,
203
208
)
204
- . await
205
- . unwrap ( )
206
- . text ;
207
-
208
- parse_diff_from_buf ( response. as_bytes ( ) , file_filter)
209
+ . await ;
210
+ match response {
211
+ Some ( response) => {
212
+ if response. status . is_success ( ) {
213
+ return parse_diff_from_buf ( response. text . as_bytes ( ) , file_filter) ;
214
+ } else {
215
+ let endpoint = if is_pr {
216
+ Url :: parse ( format ! ( "{}/files" , url. as_str( ) ) . as_str ( ) )
217
+ . expect ( "failed to parse URL endpoint" )
218
+ } else {
219
+ url
220
+ } ;
221
+ self . get_changed_files_paginated ( endpoint, file_filter)
222
+ . await
223
+ }
224
+ }
225
+ None => {
226
+ panic ! ( "Failed to connect with GitHub server to get list of changed files." )
227
+ }
228
+ }
209
229
} else {
210
230
// get diff from libgit2 API
211
231
let repo = open_repo ( "." )
@@ -215,6 +235,54 @@ impl RestApiClient for GithubApiClient {
215
235
}
216
236
}
217
237
238
+ async fn get_changed_files_paginated (
239
+ & self ,
240
+ url : Url ,
241
+ file_filter : & FileFilter ,
242
+ ) -> Vec < FileObj > {
243
+ let mut url = Some ( Url :: parse_with_params ( url. as_str ( ) , & [ ( "page" , "1" ) ] ) . unwrap ( ) ) ;
244
+ let mut files = vec ! [ ] ;
245
+ while let Some ( ref endpoint) = url {
246
+ let request =
247
+ Self :: make_api_request ( & self . client , endpoint. as_str ( ) , Method :: GET , None , None ) ;
248
+ let response = Self :: send_api_request (
249
+ self . client . clone ( ) ,
250
+ request,
251
+ true ,
252
+ self . rate_limit_headers . clone ( ) ,
253
+ 0 ,
254
+ )
255
+ . await ;
256
+ if let Some ( response) = response {
257
+ url = Self :: try_next_page ( & response. headers ) ;
258
+ let files_list = if self . event_name != "pull_request" {
259
+ let json_value: PushEventFiles = serde_json:: from_str ( & response. text )
260
+ . expect ( "Failed to deserialize list of changed files from json response" ) ;
261
+ json_value. files
262
+ } else {
263
+ serde_json:: from_str :: < Vec < GithubChangedFile > > ( & response. text ) . expect (
264
+ "Failed to deserialize list of file changes from Pull Request event." ,
265
+ )
266
+ } ;
267
+ for file in files_list {
268
+ if let Some ( patch) = file. patch {
269
+ let diff = format ! (
270
+ "diff --git a/{old} b/{new}\n --- a/{old}\n +++ b/{new}\n {patch}" ,
271
+ old = file. previous_filename. unwrap_or( file. filename. clone( ) ) ,
272
+ new = file. filename,
273
+ ) ;
274
+ if let Some ( file_obj) =
275
+ parse_diff_from_buf ( diff. as_bytes ( ) , file_filter) . first ( )
276
+ {
277
+ files. push ( file_obj. to_owned ( ) ) ;
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
283
+ files
284
+ }
285
+
218
286
async fn post_feedback (
219
287
& self ,
220
288
files : & [ Arc < Mutex < FileObj > > ] ,
@@ -671,6 +739,24 @@ impl From<Suggestion> for ReviewDiffComment {
671
739
}
672
740
}
673
741
742
+ /// A structure for deserializing a single changed file in a CI event.
743
+ #[ derive( Debug , Deserialize , PartialEq , Clone ) ]
744
+ struct GithubChangedFile {
745
+ /// The file's name (including relative path to repo root)
746
+ pub filename : String ,
747
+ /// If renamed, this will be the file's old name as a [`Some`], otherwise [`None`].
748
+ pub previous_filename : Option < String > ,
749
+ /// The individual patch that describes the file's changes.
750
+ pub patch : Option < String > ,
751
+ }
752
+
753
+ /// A structure for deserializing a Push event's changed files.
754
+ #[ derive( Debug , Deserialize , PartialEq , Clone ) ]
755
+ struct PushEventFiles {
756
+ /// The list of changed files.
757
+ pub files : Vec < GithubChangedFile > ,
758
+ }
759
+
674
760
/// A structure for deserializing a comment from a response's json.
675
761
#[ derive( Debug , Deserialize , PartialEq , Clone ) ]
676
762
struct PullRequestInfo {
@@ -840,7 +926,7 @@ mod test {
840
926
}
841
927
let request =
842
928
GithubApiClient :: make_api_request ( & client. client , url, Method :: GET , None , None ) ;
843
- let _response = GithubApiClient :: send_api_request (
929
+ GithubApiClient :: send_api_request (
844
930
client. client . clone ( ) ,
845
931
request,
846
932
true ,
0 commit comments