Reduce duplication in the logs when errors occur in CLI commands

This commit is contained in:
Henry Mercer 2023-10-06 15:53:15 +01:00
parent a2dc5ffaff
commit 8295705640
9 changed files with 71 additions and 28 deletions

6
lib/analyze.js generated
View file

@ -237,12 +237,8 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
}
}
catch (e) {
logger.info(String(e));
if (e instanceof Error) {
logger.info(e.stack);
}
statusReport.analyze_failure_language = language;
throw new CodeQLAnalysisError(statusReport, `Error running analysis for ${language}: ${e}`);
throw new CodeQLAnalysisError(statusReport, `Error running analysis for ${language}: ${util.wrapError(e).message}`);
}
}
return statusReport;

File diff suppressed because one or more lines are too long

21
lib/codeql.js generated
View file

@ -37,15 +37,25 @@ const setupCodeql = __importStar(require("./setup-codeql"));
const util = __importStar(require("./util"));
const util_1 = require("./util");
class CommandInvocationError extends Error {
constructor(cmd, args, exitCode, error, output) {
constructor(cmd, args, exitCode, stderr, stdout) {
const prettyCommand = [cmd, ...args]
.map((x) => (x.includes(" ") ? `'${x}'` : x))
.join(" ");
const fatalErrors = extractFatalErrors(stderr);
const lastLine = stderr.trim().split("\n").pop()?.trim();
let error = fatalErrors
? ` and error was: ${fatalErrors.trim()}`
: lastLine
? ` and last log line was: ${lastLine}`
: "";
if (error[error.length - 1] !== ".") {
error += ".";
}
super(`Encountered a fatal error while running "${prettyCommand}". ` +
`Exit code was ${exitCode} and error was: ${error.trim()}`);
`Exit code was ${exitCode}${error} See the logs for more details.`);
this.exitCode = exitCode;
this.error = error;
this.output = output;
this.stderr = stderr;
this.stdout = stdout;
}
}
exports.CommandInvocationError = CommandInvocationError;
@ -775,7 +785,6 @@ async function runTool(cmd, args = [], opts = {}) {
...(opts.stdin ? { input: Buffer.from(opts.stdin || "") } : {}),
}).exec();
if (exitCode !== 0) {
error = extractFatalErrors(error) || error;
throw new CommandInvocationError(cmd, args, exitCode, error, output);
}
return output;
@ -956,7 +965,7 @@ function isNoCodeFoundError(e) {
* This can be removed once support for CodeQL 2.11.6 is removed.
*/
const javascriptNoCodeFoundWarning = "No JavaScript or TypeScript code found.";
return e.exitCode === 32 || e.error.includes(javascriptNoCodeFoundWarning);
return e.exitCode === 32 || e.stderr.includes(javascriptNoCodeFoundWarning);
}
async function isDiagnosticsExportInvalidSarifFixed(codeql) {
return await util.codeQlVersionAbove(codeql, exports.CODEQL_VERSION_DIAGNOSTICS_EXPORT_FIXED);

File diff suppressed because one or more lines are too long

16
lib/codeql.test.js generated
View file

@ -695,7 +695,7 @@ for (const { featureEnabled, codeqlVersion, flagPassed, negativeFlagPassed, } of
sinon.stub(safeWhich, "safeWhich").resolves("");
await t.throwsAsync(async () => await codeqlObject.finalizeDatabase("db", "--threads=2", "--ram=2048"), {
message: 'Encountered a fatal error while running "codeql-for-testing database finalize --finalize-dataset --threads=2 --ram=2048 db". ' +
`Exit code was 32 and error was: ${cliMessage}`,
`Exit code was 32 and last log line was: ${cliMessage} See the logs for more details.`,
});
});
(0, ava_1.default)("runTool summarizes several fatal errors", async (t) => {
@ -710,7 +710,19 @@ for (const { featureEnabled, codeqlVersion, flagPassed, negativeFlagPassed, } of
sinon.stub(safeWhich, "safeWhich").resolves("");
await t.throwsAsync(async () => await codeqlObject.finalizeDatabase("db", "--threads=2", "--ram=2048"), {
message: 'Encountered a fatal error while running "codeql-for-testing database finalize --finalize-dataset --threads=2 --ram=2048 db". ' +
`Exit code was 32 and error was: ${datasetImportError}. Context: ${heapError}.`,
`Exit code was 32 and error was: ${datasetImportError}. Context: ${heapError}. See the logs for more details.`,
});
});
(0, ava_1.default)("runTool outputs last line of stderr if fatal error could not be found", async (t) => {
const cliStderr = "line1\nline2\nline3\nline4\nline5";
stubToolRunnerConstructor(32, cliStderr);
const codeqlObject = await codeql.getCodeQLForTesting();
sinon.stub(codeqlObject, "getVersion").resolves((0, testing_utils_1.makeVersionInfo)("2.12.4"));
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await t.throwsAsync(async () => await codeqlObject.finalizeDatabase("db", "--threads=2", "--ram=2048"), {
message: 'Encountered a fatal error while running "codeql-for-testing database finalize --finalize-dataset --threads=2 --ram=2048 db". ' +
"Exit code was 32 and last log line was: line5. See the logs for more details.",
});
});
function stubToolRunnerConstructor(exitCode = 0, stderr) {

File diff suppressed because one or more lines are too long

View file

@ -394,14 +394,10 @@ export async function runQueries(
await runPrintLinesOfCode(language);
}
} catch (e) {
logger.info(String(e));
if (e instanceof Error) {
logger.info(e.stack!);
}
statusReport.analyze_failure_language = language;
throw new CodeQLAnalysisError(
statusReport,
`Error running analysis for ${language}: ${e}`,
`Error running analysis for ${language}: ${util.wrapError(e).message}`,
);
}
}

View file

@ -1133,7 +1133,7 @@ test("database finalize does not override no code found error on CodeQL 2.12.4",
{
message:
'Encountered a fatal error while running "codeql-for-testing database finalize --finalize-dataset --threads=2 --ram=2048 db". ' +
`Exit code was 32 and error was: ${cliMessage}`,
`Exit code was 32 and last log line was: ${cliMessage} See the logs for more details.`,
},
);
});
@ -1158,7 +1158,26 @@ test("runTool summarizes several fatal errors", async (t) => {
{
message:
'Encountered a fatal error while running "codeql-for-testing database finalize --finalize-dataset --threads=2 --ram=2048 db". ' +
`Exit code was 32 and error was: ${datasetImportError}. Context: ${heapError}.`,
`Exit code was 32 and error was: ${datasetImportError}. Context: ${heapError}. See the logs for more details.`,
},
);
});
test("runTool outputs last line of stderr if fatal error could not be found", async (t) => {
const cliStderr = "line1\nline2\nline3\nline4\nline5";
stubToolRunnerConstructor(32, cliStderr);
const codeqlObject = await codeql.getCodeQLForTesting();
sinon.stub(codeqlObject, "getVersion").resolves(makeVersionInfo("2.12.4"));
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await t.throwsAsync(
async () =>
await codeqlObject.finalizeDatabase("db", "--threads=2", "--ram=2048"),
{
message:
'Encountered a fatal error while running "codeql-for-testing database finalize --finalize-dataset --threads=2 --ram=2048 db". ' +
"Exit code was 32 and last log line was: line5. See the logs for more details.",
},
);
});

View file

@ -54,15 +54,27 @@ export class CommandInvocationError extends Error {
cmd: string,
args: string[],
public exitCode: number,
public error: string,
public output: string,
public stderr: string,
public stdout: string,
) {
const prettyCommand = [cmd, ...args]
.map((x) => (x.includes(" ") ? `'${x}'` : x))
.join(" ");
const fatalErrors = extractFatalErrors(stderr);
const lastLine = stderr.trim().split("\n").pop()?.trim();
let error = fatalErrors
? ` and error was: ${fatalErrors.trim()}`
: lastLine
? ` and last log line was: ${lastLine}`
: "";
if (error[error.length - 1] !== ".") {
error += ".";
}
super(
`Encountered a fatal error while running "${prettyCommand}". ` +
`Exit code was ${exitCode} and error was: ${error.trim()}`,
`Exit code was ${exitCode}${error} See the logs for more details.`,
);
}
}
@ -1238,7 +1250,6 @@ async function runTool(
...(opts.stdin ? { input: Buffer.from(opts.stdin || "") } : {}),
}).exec();
if (exitCode !== 0) {
error = extractFatalErrors(error) || error;
throw new CommandInvocationError(cmd, args, exitCode, error, output);
}
return output;
@ -1454,7 +1465,7 @@ function isNoCodeFoundError(e: CommandInvocationError): boolean {
*/
const javascriptNoCodeFoundWarning =
"No JavaScript or TypeScript code found.";
return e.exitCode === 32 || e.error.includes(javascriptNoCodeFoundWarning);
return e.exitCode === 32 || e.stderr.includes(javascriptNoCodeFoundWarning);
}
async function isDiagnosticsExportInvalidSarifFixed(