Skip to content

Commit 99feda8

Browse files
committed
view-autofixes: refactor external command execution
1 parent 35d636e commit 99feda8

File tree

1 file changed

+55
-47
lines changed

1 file changed

+55
-47
lines changed

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

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -802,14 +802,14 @@ async function runAutofixOnResults(
802802
}
803803

804804
/**
805-
* Executes the autofix command.
805+
* Spawns an external process and collects its output.
806806
*/
807-
function execAutofix(
807+
function execCommand(
808808
bin: string,
809809
args: string[],
810810
options: Parameters<typeof execFileSync>[2],
811811
showCommand?: boolean,
812-
): Promise<void> {
812+
): Promise<{ code: number | null; stdout: string; stderr: string }> {
813813
return new Promise((resolve, reject) => {
814814
try {
815815
const cwd = options?.cwd || process.cwd();
@@ -842,61 +842,69 @@ function execAutofix(
842842

843843
// Listen for process exit
844844
p.on("exit", (code) => {
845-
// Log collected output
846-
if (stdoutBuffer.trim()) {
847-
void extLogger.log(`Autofix stdout:\n${stdoutBuffer.trim()}`);
848-
}
849-
850-
if (stderrBuffer.trim()) {
851-
void extLogger.log(`Autofix stderr:\n${stderrBuffer.trim()}`);
852-
}
853-
854-
if (code === 0) {
855-
resolve();
856-
} else {
857-
reject(new Error(`Autofix process exited with code ${code}.`));
858-
}
845+
resolve({
846+
code,
847+
stdout: stdoutBuffer.trim(),
848+
stderr: stderrBuffer.trim(),
849+
});
859850
});
860851
} catch (e) {
861852
reject(asError(e));
862853
}
863854
});
864855
}
865856

866-
/** Execute the 1Password CLI command `op read <secretReference>`, if the `op` command exists on the PATH. */
867-
async function opRead(secretReference: string): Promise<string> {
868-
return new Promise((resolve, reject) => {
869-
const opProcess = spawn("op", ["read", secretReference], {
870-
stdio: ["ignore", "pipe", "pipe"],
871-
});
872-
873-
let stdoutBuffer = "";
874-
let stderrBuffer = "";
857+
/**
858+
* Executes the autofix command.
859+
*/
860+
async function execAutofix(
861+
bin: string,
862+
args: string[],
863+
options: Parameters<typeof execFileSync>[2],
864+
showCommand?: boolean,
865+
): Promise<void> {
866+
const { code, stdout, stderr } = await execCommand(
867+
bin,
868+
args,
869+
options,
870+
showCommand,
871+
);
875872

876-
opProcess.stdout?.on("data", (data) => {
877-
stdoutBuffer += data.toString();
878-
});
873+
if (code !== 0) throw new Error(`Autofix process exited with code ${code}.`);
879874

880-
opProcess.stderr?.on("data", (data) => {
881-
stderrBuffer += data.toString();
882-
});
875+
// Log collected output
876+
if (stdout) {
877+
void extLogger.log(`Autofix stdout:\n${stdout}`);
878+
}
879+
if (stderr) {
880+
void extLogger.log(`Autofix stderr:\n${stderr}`);
881+
}
882+
}
883883

884-
opProcess.on("error", (error) => {
885-
reject(error);
886-
});
884+
/** Execute the 1Password CLI command `op read <secretReference>`, if the `op` command exists on the PATH. */
885+
async function opRead(secretReference: string): Promise<string> {
886+
try {
887+
const { code, stdout, stderr } = await execCommand(
888+
"op",
889+
["read", secretReference],
890+
{},
891+
false,
892+
);
887893

888-
opProcess.on("exit", (code) => {
889-
if (code === 0) {
890-
resolve(stdoutBuffer.trim());
891-
} else {
892-
reject(
893-
new Error(
894-
`1Password CLI exited with code ${code}. Stderr: ${stderrBuffer.trim()}`,
895-
),
896-
);
897-
}
898-
});
899-
});
894+
if (code === 0) {
895+
return stdout;
896+
} else {
897+
throw new Error(
898+
`1Password CLI exited with code ${code}. Stderr: ${stderr}`,
899+
);
900+
}
901+
} catch (e) {
902+
const error = asError(e);
903+
if ("code" in error && error.code === "ENOENT") {
904+
throw new Error("1Password CLI (op) not found in PATH");
905+
}
906+
throw e;
907+
}
900908
}
901909

902910
/**

0 commit comments

Comments
 (0)