@@ -20,7 +20,7 @@ import { window as Window } from "vscode";
2020import { pluralize } from "../common/word" ;
2121import { glob } from "glob" ;
2222import { readRepoTask } from "./repo-tasks-store" ;
23- import { unlink , mkdtemp } from "fs/promises" ;
23+ import { unlink , mkdtemp , readFile , writeFile } from "fs/promises" ;
2424import { tmpdir } from "os" ;
2525import { spawn } from "child_process" ;
2626import type { execFileSync } from "child_process" ;
@@ -508,9 +508,45 @@ async function runAutofixForRepository(
508508
509509 // Run autofix in a loop for the first MAX_NUM_FIXES alerts.
510510 // Not an ideal solution, but avoids modifying the input SARIF file.
511+ const tempOutputTextFiles : string [ ] = [ ] ;
512+ const fixDescriptionFiles : string [ ] = [ ] ;
513+ const transcriptFiles : string [ ] = [ ] ;
511514 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+ ) ;
513543 }
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 ) ;
514550 } else {
515551 // Run autofix once for all alerts.
516552 await runAutofixOnResults (
@@ -673,3 +709,44 @@ function appendSuffixToFilePath(filePath: string, suffix: string): string {
673709 const { dir, name, ext } = parse ( filePath ) ;
674710 return join ( dir , `${ name } -${ suffix } ${ ext } ` ) ;
675711}
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