@@ -192,20 +192,40 @@ impl RestApiClient for GithubApiClient {
192192 . unwrap ( ) ;
193193 let mut diff_header = HeaderMap :: new ( ) ;
194194 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+ ) ;
197202 let response = Self :: send_api_request (
198203 self . client . clone ( ) ,
199204 request,
200- true ,
205+ false ,
201206 self . rate_limit_headers . to_owned ( ) ,
202207 0 ,
203208 )
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+ }
209229 } else {
210230 // get diff from libgit2 API
211231 let repo = open_repo ( "." )
@@ -215,6 +235,54 @@ impl RestApiClient for GithubApiClient {
215235 }
216236 }
217237
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+
218286 async fn post_feedback (
219287 & self ,
220288 files : & [ Arc < Mutex < FileObj > > ] ,
@@ -671,6 +739,24 @@ impl From<Suggestion> for ReviewDiffComment {
671739 }
672740}
673741
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+
674760/// A structure for deserializing a comment from a response's json.
675761#[ derive( Debug , Deserialize , PartialEq , Clone ) ]
676762struct PullRequestInfo {
@@ -840,7 +926,7 @@ mod test {
840926 }
841927 let request =
842928 GithubApiClient :: make_api_request ( & client. client , url, Method :: GET , None , None ) ;
843- let _response = GithubApiClient :: send_api_request (
929+ GithubApiClient :: send_api_request (
844930 client. client . clone ( ) ,
845931 request,
846932 true ,
0 commit comments