@@ -20,7 +20,7 @@ import { window as Window } from "vscode";
20
20
import { pluralize } from "../common/word" ;
21
21
import { glob } from "glob" ;
22
22
import { readRepoTask } from "./repo-tasks-store" ;
23
- import { unlink , mkdtemp } from "fs/promises" ;
23
+ import { unlink , mkdtemp , readFile , writeFile } from "fs/promises" ;
24
24
import { tmpdir } from "os" ;
25
25
import { spawn } from "child_process" ;
26
26
import type { execFileSync } from "child_process" ;
@@ -508,9 +508,45 @@ async function runAutofixForRepository(
508
508
509
509
// Run autofix in a loop for the first MAX_NUM_FIXES alerts.
510
510
// Not an ideal solution, but avoids modifying the input SARIF file.
511
+ const tempOutputTextFiles : string [ ] = [ ] ;
512
+ const fixDescriptionFiles : string [ ] = [ ] ;
513
+ const transcriptFiles : string [ ] = [ ] ;
511
514
for ( let i = 0 ; i < MAX_NUM_FIXES ; i ++ ) {
512
- // TODO: run autofix for the i-th alert.
515
+ const tempOutputTextFilePath = appendSuffixToFilePath (
516
+ outputTextFilePath ,
517
+ i . toString ( ) ,
518
+ ) ;
519
+ const tempFixDescriptionFilePath = appendSuffixToFilePath (
520
+ fixDescriptionFilePath ,
521
+ i . toString ( ) ,
522
+ ) ;
523
+ const tempTranscriptFilePath = appendSuffixToFilePath (
524
+ transcriptFilePath ,
525
+ i . toString ( ) ,
526
+ ) ;
527
+
528
+ tempOutputTextFiles . push ( tempOutputTextFilePath ) ;
529
+ fixDescriptionFiles . push ( tempFixDescriptionFilePath ) ;
530
+ transcriptFiles . push ( tempTranscriptFilePath ) ;
531
+
532
+ await runAutofixOnResults (
533
+ logger ,
534
+ cocofixBin ,
535
+ sarifFile ,
536
+ srcRootPath ,
537
+ tempOutputTextFilePath ,
538
+ tempFixDescriptionFilePath ,
539
+ tempTranscriptFilePath ,
540
+ repoAutofixOutputStoragePath ,
541
+ i ,
542
+ ) ;
513
543
}
544
+
545
+ // Merge the output files together.
546
+ // Caveat that autofix will call each alert "alert 0", which will look a bit odd in the merged output file.
547
+ await mergeFiles ( tempOutputTextFiles , outputTextFilePath ) ;
548
+ await mergeFiles ( fixDescriptionFiles , fixDescriptionFilePath ) ;
549
+ await mergeFiles ( transcriptFiles , transcriptFilePath ) ;
514
550
} else {
515
551
// Run autofix once for all alerts.
516
552
await runAutofixOnResults (
@@ -673,3 +709,44 @@ function appendSuffixToFilePath(filePath: string, suffix: string): string {
673
709
const { dir, name, ext } = parse ( filePath ) ;
674
710
return join ( dir , `${ name } -${ suffix } ${ ext } ` ) ;
675
711
}
712
+
713
+ /**
714
+ * Merges the given `inputFiles` into a single `outputFile`.
715
+ * @param inputFiles - The list of input files to merge.
716
+ * @param outputFile - The output file path.
717
+ * @param deleteOriginalFiles - Whether to delete the original input files after merging.
718
+ */
719
+ async function mergeFiles (
720
+ inputFiles : string [ ] ,
721
+ outputFile : string ,
722
+ deleteOriginalFiles : boolean = true ,
723
+ ) : Promise < void > {
724
+ try {
725
+ // Check if any input files do not exist and return if so.
726
+ const pathChecks = await Promise . all (
727
+ inputFiles . map ( async ( path ) => ( {
728
+ exists : await pathExists ( path ) ,
729
+ } ) ) ,
730
+ ) ;
731
+ const anyPathMissing = pathChecks . some ( ( check ) => ! check . exists ) ;
732
+ if ( inputFiles . length === 0 || anyPathMissing ) {
733
+ return ;
734
+ }
735
+
736
+ // Merge the files
737
+ const contents = await Promise . all (
738
+ inputFiles . map ( ( file ) => readFile ( file , "utf8" ) ) ,
739
+ ) ;
740
+
741
+ // Write merged content
742
+ await writeFile ( outputFile , contents . join ( "\n" ) ) ;
743
+
744
+ // Delete original files
745
+ if ( deleteOriginalFiles ) {
746
+ await Promise . all ( inputFiles . map ( ( file ) => unlink ( file ) ) ) ;
747
+ }
748
+ } catch ( error ) {
749
+ console . error ( "Error merging files:" , error ) ;
750
+ throw error ;
751
+ }
752
+ }
0 commit comments