@@ -266,121 +266,6 @@ pub async fn execute_command(command: &str, suppress_error: bool) -> String {
266
266
stdout. to_string ( )
267
267
}
268
268
269
- fn save_commit_map (
270
- file_commit_map : & HashMap < String , String > ,
271
- ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
272
- let commit_map_path = "/tmp/commit_map.json" ;
273
- let file = File :: create ( commit_map_path) ?;
274
- serde_json:: to_writer ( file, file_commit_map) ?;
275
- println ! ( "Commit map saved to: {}" , commit_map_path) ;
276
- Ok ( ( ) )
277
- }
278
-
279
- fn delete_except ( files : & str , base_dir : & Path ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
280
- println ! ( "Deleting all files except the following:" ) ;
281
- println ! ( "__________________________________________ {:?}" , files) ;
282
- let files_to_keep: Vec < PathBuf > = files
283
- . lines ( )
284
- . map ( |line| base_dir. join ( line. trim ( ) ) )
285
- . collect ( ) ;
286
-
287
- traverse_and_delete ( base_dir, & files_to_keep) ?;
288
-
289
- Ok ( ( ) )
290
- }
291
-
292
- fn traverse_and_delete ( base_dir : & Path , files_to_keep : & [ PathBuf ] ) -> Result < ( ) , std:: io:: Error > {
293
- for entry in fs:: read_dir ( base_dir) ? {
294
- let entry = entry?;
295
- let path = entry. path ( ) ;
296
-
297
- // Skip the .git directory
298
- if path. is_dir ( ) && path. file_name ( ) . map_or ( false , |name| name == ".git" ) {
299
- continue ;
300
- }
301
-
302
- if path. is_dir ( ) {
303
- traverse_and_delete ( & path, files_to_keep) ?;
304
- }
305
-
306
- // Check if the path should be deleted (only delete files)
307
- if path. is_file ( ) && !files_to_keep. contains ( & path. canonicalize ( ) ?) {
308
- fs:: remove_file ( & path) ?;
309
- }
310
- }
311
-
312
- Ok ( ( ) )
313
- }
314
-
315
- fn delete_empty_directories ( start_dir : & Path ) -> Result < ( ) , std:: io:: Error > {
316
- for entry in fs:: read_dir ( start_dir) ? {
317
- let entry = entry?;
318
- let path = entry. path ( ) ;
319
-
320
- // Skip the .git directory
321
- if path. is_dir ( ) && path. file_name ( ) . map_or ( false , |name| name == ".git" ) {
322
- continue ;
323
- }
324
-
325
- if path. is_dir ( ) {
326
- delete_empty_directories ( & path) ?;
327
- if fs:: read_dir ( & path) ?. next ( ) . is_none ( ) {
328
- fs:: remove_dir ( & path) ?;
329
- }
330
- }
331
- }
332
-
333
- Ok ( ( ) )
334
- }
335
-
336
- fn get_cumulative_pr_files (
337
- base_branch : Option < & str > ,
338
- pr_branch : Option < & str > ,
339
- ) -> Result < Vec < String > , Box < dyn std:: error:: Error > > {
340
- if let Some ( base) = base_branch {
341
- // Step 1: Create and checkout a temporary branch from the base branch
342
- Command :: new ( "git" ) . args ( & [ "checkout" , base] ) . output ( ) ?;
343
- Command :: new ( "git" )
344
- . args ( & [ "checkout" , "-b" , "temp_pr_merge_branch" ] )
345
- . output ( ) ?;
346
-
347
- if let Some ( pr) = pr_branch {
348
- // Step 2: Merge the PR branch without fast-forwarding
349
- let merge_output = Command :: new ( "git" )
350
- . args ( & [ "merge" , "--no-ff" , pr] )
351
- . output ( ) ?;
352
- if !merge_output. status . success ( ) {
353
- let error_msg = String :: from_utf8_lossy ( & merge_output. stderr ) ;
354
- return Err ( format ! ( "Failed to merge PR branch: {}" , error_msg) . into ( ) ) ;
355
- }
356
-
357
- // Step 3: Get the list of changed files in the cumulative diff
358
- let output = Command :: new ( "git" )
359
- . args ( & [ "diff" , "--name-only" , base, "temp_pr_merge_branch" ] )
360
- . output ( ) ?;
361
- if !output. status . success ( ) {
362
- let error_msg = String :: from_utf8_lossy ( & output. stderr ) ;
363
- return Err ( format ! ( "Failed to get cumulative PR files: {}" , error_msg) . into ( ) ) ;
364
- }
365
-
366
- let files = String :: from_utf8_lossy ( & output. stdout ) ;
367
- let file_names = files. lines ( ) . map ( String :: from) . collect ( ) ;
368
-
369
- // Cleanup: Delete the temporary branch
370
- Command :: new ( "git" ) . args ( & [ "checkout" , base] ) . output ( ) ?;
371
- Command :: new ( "git" )
372
- . args ( & [ "branch" , "-D" , "temp_pr_merge_branch" ] )
373
- . output ( ) ?;
374
-
375
- Ok ( file_names)
376
- } else {
377
- Err ( "PR branch is required when base branch is specified." . into ( ) )
378
- }
379
- } else {
380
- Err ( "Base branch is required." . into ( ) )
381
- }
382
- }
383
-
384
269
pub fn checkout (
385
270
clone_url : & str ,
386
271
clone_path : & str ,
@@ -401,16 +286,20 @@ pub fn checkout(
401
286
402
287
// Set the working directory to the cloned path
403
288
let cloned_path = Path :: new ( clone_path) . canonicalize ( ) ?;
289
+ let repo_path = cloned_path. to_str ( ) . unwrap ( ) ;
404
290
env:: set_current_dir ( & cloned_path) ?;
405
291
406
292
// Configure Git user for commits in this repository
407
293
Command :: new ( "git" )
408
- . args ( & [ "config" , "user.email" , "ci@hela.int " ] )
294
+ . args ( & [ "config" , "user.email" , "ci@example.com " ] )
409
295
. output ( ) ?;
410
296
Command :: new ( "git" )
411
297
. args ( & [ "config" , "user.name" , "CI Bot" ] )
412
298
. output ( ) ?;
413
299
300
+ // Store the set of changed files
301
+ let mut changed_files = HashSet :: new ( ) ;
302
+
414
303
// If a pr_branch is provided, fetch it as a local branch and compare with the base branch
415
304
if let Some ( pr_branch_name) = pr_branch {
416
305
// Fetch the PR branch and create a local branch
@@ -441,16 +330,11 @@ pub fn checkout(
441
330
return Err ( format ! ( "Failed to diff branches: {}" , error_msg) . into ( ) ) ;
442
331
}
443
332
444
- // Parse the diff output
445
- let changed_files = String :: from_utf8_lossy ( & diff_output. stdout )
446
- . lines ( )
447
- . map ( String :: from)
448
- . collect :: < Vec < String > > ( ) ;
449
-
450
- println ! (
451
- "Changed files in PR branch '{}': {:?}" ,
452
- pr_branch_name, changed_files
453
- ) ;
333
+ // Parse the diff output into a set of changed files
334
+ let diff_output_str = String :: from_utf8_lossy ( & diff_output. stdout ) ;
335
+ for line in diff_output_str. lines ( ) {
336
+ changed_files. insert ( line. trim ( ) . to_string ( ) ) ;
337
+ }
454
338
} else {
455
339
// If no PR branch, list all files in the base branch
456
340
let list_output = Command :: new ( "git" )
@@ -462,18 +346,79 @@ pub fn checkout(
462
346
return Err ( format ! ( "Failed to list files in base branch: {}" , error_msg) . into ( ) ) ;
463
347
}
464
348
465
- let files = String :: from_utf8_lossy ( & list_output. stdout )
466
- . lines ( )
467
- . map ( String :: from)
468
- . collect :: < Vec < String > > ( ) ;
349
+ // Parse the list output into a set of files
350
+ let list_output_str = String :: from_utf8_lossy ( & list_output. stdout ) ;
351
+ for line in list_output_str. lines ( ) {
352
+ changed_files. insert ( line. trim ( ) . to_string ( ) ) ;
353
+ }
354
+ }
355
+
356
+ // Print the changed files for debugging purposes
357
+ println ! ( "Changed files:\n {:#?}" , changed_files) ;
469
358
470
- println ! (
471
- "Files in branch '{}': {:?}" ,
472
- branch. unwrap_or( "default branch" ) ,
473
- files
474
- ) ;
359
+ // Ensure the working directory is up-to-date before checking out files
360
+ Command :: new ( "git" )
361
+ . args ( & [ "checkout" , pr_branch. unwrap_or ( "HEAD" ) ] )
362
+ . output ( ) ?;
363
+
364
+ // Ensure each changed file is checked out from the PR branch
365
+ for file in & changed_files {
366
+ let checkout_output = Command :: new ( "git" )
367
+ . args ( & [ "checkout" , pr_branch. unwrap_or ( "HEAD" ) , "--" , file] )
368
+ . output ( ) ?;
369
+
370
+ if !checkout_output. status . success ( ) {
371
+ let error_msg = String :: from_utf8_lossy ( & checkout_output. stderr ) ;
372
+ println ! ( "Failed to checkout file '{}': {}" , file, error_msg) ;
373
+ }
475
374
}
476
375
376
+ // Remove all files not in the `changed_files` set
377
+ remove_unwanted_files ( repo_path, & changed_files) ?;
378
+
379
+ println ! ( "Only the changed files have been kept locally." ) ;
380
+
381
+ Ok ( ( ) )
382
+ }
383
+
384
+ /// Removes all files that are not in the `files_to_keep` set, but preserves directories.
385
+ ///
386
+ /// # Arguments
387
+ ///
388
+ /// * `repo_path` - The path of the repository.
389
+ /// * `files_to_keep` - A set of file paths to keep relative to the `repo_path`.
390
+ fn remove_unwanted_files (
391
+ repo_path : & str ,
392
+ files_to_keep : & HashSet < String > ,
393
+ ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
394
+ // Recursively remove unwanted files
395
+ for entry in fs:: read_dir ( repo_path) ? {
396
+ let entry = entry?;
397
+ let path = entry. path ( ) ;
398
+
399
+ // Skip the .git directory to preserve repository integrity
400
+ if path. is_dir ( ) && path. file_name ( ) . map_or ( false , |name| name == ".git" ) {
401
+ continue ;
402
+ }
403
+
404
+ // Determine the relative path
405
+ let relative_path = path. strip_prefix ( repo_path) ?. to_str ( ) . unwrap ( ) . to_string ( ) ;
406
+
407
+ // Check if the file should be kept or removed
408
+ if path. is_file ( ) && !files_to_keep. contains ( & relative_path) {
409
+ println ! ( "Removing file: {}" , relative_path) ;
410
+ fs:: remove_file ( & path) ?;
411
+ } else if path. is_dir ( ) {
412
+ // Recursively clean up subdirectories
413
+ remove_unwanted_files ( path. to_str ( ) . unwrap ( ) , files_to_keep) ?;
414
+
415
+ // Check if the directory is empty and remove it
416
+ if fs:: read_dir ( & path) ?. next ( ) . is_none ( ) {
417
+ println ! ( "Removing empty directory: {}" , relative_path) ;
418
+ fs:: remove_dir ( & path) ?;
419
+ }
420
+ }
421
+ }
477
422
Ok ( ( ) )
478
423
}
479
424
0 commit comments