Skip to content

Commit e04eb62

Browse files
Jami CogswellJami Cogswell
authored andcommitted
Run autofix for case when the repo result count exceeds the fix limit
1 parent e7076f9 commit e04eb62

File tree

1 file changed

+79
-2
lines changed

1 file changed

+79
-2
lines changed

extensions/ql-vscode/src/variant-analysis/view-autofixes.ts

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { window as Window } from "vscode";
2020
import { pluralize } from "../common/word";
2121
import { glob } from "glob";
2222
import { readRepoTask } from "./repo-tasks-store";
23-
import { unlink, mkdtemp } from "fs/promises";
23+
import { unlink, mkdtemp, readFile, writeFile } from "fs/promises";
2424
import { tmpdir } from "os";
2525
import { spawn } from "child_process";
2626
import 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

Comments
 (0)