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