@@ -2884,6 +2884,18 @@ async function prepareReviewContext(
28842884 }
28852885 const files = await githubRequestAllPages ( `https://api.github.com/repos/${ repo } /pulls/${ prNumber } /files` , token ) ;
28862886
2887+ const fetchBase = runCommand ( [ config . hostGitBin , "fetch" , "--depth" , "1" , "origin" , liveBase ] , workspace , env , 180 ) ;
2888+ writeJsonAtomic ( join ( attemptDir , "fetch-pr-base.json" ) , redactedCommandResult ( fetchBase ) ) ;
2889+ if ( fetchBase . returncode !== 0 ) {
2890+ return {
2891+ kind : "pull_request" ,
2892+ pr_number : prNumber ,
2893+ fetch_error : fetchBase . stderr ,
2894+ metadata : summarizePr ( pr ) ,
2895+ files : summarizePrFiles ( files , new Map ( ) ) ,
2896+ } ;
2897+ }
2898+
28872899 const fetch = runCommand ( [ config . hostGitBin , "fetch" , "--depth" , "1" , "origin" , `pull/${ prNumber } /head` ] , workspace , env , 180 ) ;
28882900 writeJsonAtomic ( join ( attemptDir , "fetch-pr.json" ) , redactedCommandResult ( fetch ) ) ;
28892901 if ( fetch . returncode !== 0 ) {
@@ -2892,7 +2904,7 @@ async function prepareReviewContext(
28922904 pr_number : prNumber ,
28932905 fetch_error : fetch . stderr ,
28942906 metadata : summarizePr ( pr ) ,
2895- files : summarizePrFiles ( files ) ,
2907+ files : summarizePrFiles ( files , new Map ( ) ) ,
28962908 } ;
28972909 }
28982910
@@ -2913,11 +2925,37 @@ async function prepareReviewContext(
29132925 spawn_error : [ head . spawn_error , status . spawn_error ] . filter ( Boolean ) . join ( "\n" ) ,
29142926 } ) ) ;
29152927
2928+ const localPatches = new Map < string , CommandResult > ( ) ;
2929+ const localPatchEvidence : JsonObject [ ] = [ ] ;
2930+ for ( const file of files ) {
2931+ const filename = String ( file . filename || "" ) ;
2932+ if ( ! filename ) continue ;
2933+ const diffPaths = [ ...new Set ( [ String ( file . previous_filename || "" ) , filename ] . filter ( Boolean ) ) ] ;
2934+ const diff = runCommand (
2935+ [ config . hostGitBin , "diff" , "--no-ext-diff" , "--unified=3" , liveBase , liveHead , "--" , ...diffPaths ] ,
2936+ workspace ,
2937+ env ,
2938+ 180 ,
2939+ ) ;
2940+ localPatches . set ( filename , diff ) ;
2941+ localPatchEvidence . push ( {
2942+ filename,
2943+ paths : diffPaths ,
2944+ returncode : diff . returncode ,
2945+ patch_bytes : Buffer . byteLength ( diff . stdout , "utf8" ) ,
2946+ patch_sha256 : diff . returncode === 0 ? sha256 ( diff . stdout ) : undefined ,
2947+ stderr : redactTokenish ( diff . stderr ) ,
2948+ timed_out : diff . timed_out ,
2949+ spawn_error : diff . spawn_error ,
2950+ } ) ;
2951+ }
2952+ writeJsonAtomic ( join ( attemptDir , "local-pr-diff-evidence.json" ) , localPatchEvidence ) ;
2953+
29162954 return {
29172955 kind : "pull_request" ,
29182956 pr_number : prNumber ,
29192957 metadata : summarizePr ( pr ) ,
2920- files : summarizePrFiles ( files ) ,
2958+ files : summarizePrFiles ( files , localPatches ) ,
29212959 checkout : {
29222960 fetch_returncode : fetch . returncode ,
29232961 checkout_returncode : checkout . returncode ,
@@ -2944,19 +2982,30 @@ function summarizePr(pr: JsonObject): JsonObject {
29442982 } ;
29452983}
29462984
2947- function summarizePrFiles ( files : JsonObject [ ] ) : JsonObject [ ] {
2985+ export function summarizePrFiles ( files : JsonObject [ ] , localPatches ?: ReadonlyMap < string , CommandResult > ) : JsonObject [ ] {
29482986 return ( files || [ ] ) . map ( ( item ) => {
2949- const patch = String ( item . patch || "" ) ;
2987+ const filename = String ( item . filename || "" ) ;
2988+ const localPatch = localPatches ?. get ( filename ) ;
2989+ const localCaptureRequired = localPatches !== undefined ;
2990+ const localCaptureSucceeded = localPatch ?. returncode === 0 ;
2991+ const patch = localCaptureSucceeded ? localPatch . stdout : String ( item . patch || "" ) ;
29502992 const patchTruncated = patchEvidenceIncomplete ( patch , Number ( item . additions || 0 ) , Number ( item . deletions || 0 ) ) ;
2993+ const binaryPatch = patch . includes ( "GIT binary patch" ) || patch . includes ( "Binary files " ) ;
29512994 return {
2952- filename : item . filename ,
2995+ filename,
29532996 status : item . status ,
29542997 additions : item . additions ,
29552998 deletions : item . deletions ,
29562999 changes : item . changes ,
29573000 sha : item . sha ,
2958- patch : patch . slice ( 0 , 12000 ) ,
2959- patch_truncated : patch . length > 12000 || patchTruncated ,
3001+ patch : localCaptureSucceeded ? patch : patch . slice ( 0 , 12000 ) ,
3002+ patch_source : localCaptureSucceeded ? "local_exact_base_head" : "github_files_api" ,
3003+ patch_sha256 : patch ? sha256 ( patch ) : undefined ,
3004+ patch_truncated : ! patch . trim ( )
3005+ || binaryPatch
3006+ || patchTruncated
3007+ || ( ! localCaptureSucceeded && patch . length > 12000 )
3008+ || ( localCaptureRequired && ! localCaptureSucceeded ) ,
29603009 } ;
29613010 } ) ;
29623011}
0 commit comments