Merge branch 'main' into henrymercer/report-failed-runs
This commit is contained in:
commit
e0ff272230
21 changed files with 137 additions and 85 deletions
2
lib/analyze-action.js
generated
2
lib/analyze-action.js
generated
|
|
@ -210,7 +210,6 @@ async function run() {
|
||||||
hasBadExpectErrorInput()) {
|
hasBadExpectErrorInput()) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
console.log(error);
|
|
||||||
if (error instanceof analyze_1.CodeQLAnalysisError) {
|
if (error instanceof analyze_1.CodeQLAnalysisError) {
|
||||||
const stats = { ...error.queriesStatusReport };
|
const stats = { ...error.queriesStatusReport };
|
||||||
await sendStatusReport(startedAt, config, stats, error, trapCacheUploadTime, dbCreationTimings, didUploadTrapCaches, logger);
|
await sendStatusReport(startedAt, config, stats, error, trapCacheUploadTime, dbCreationTimings, didUploadTrapCaches, logger);
|
||||||
|
|
@ -240,7 +239,6 @@ async function runWrapper() {
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.setFailed(`analyze action failed: ${error}`);
|
core.setFailed(`analyze action failed: ${error}`);
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
await (0, util_1.checkForTimeout)();
|
await (0, util_1.checkForTimeout)();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
16
lib/codeql.js
generated
16
lib/codeql.js
generated
|
|
@ -667,7 +667,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
||||||
if (querySuitePath) {
|
if (querySuitePath) {
|
||||||
codeqlArgs.push(querySuitePath);
|
codeqlArgs.push(querySuitePath);
|
||||||
}
|
}
|
||||||
await runTool(cmd, codeqlArgs);
|
await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)(cmd, codeqlArgs, error_matcher_1.errorMatchers);
|
||||||
},
|
},
|
||||||
async databaseInterpretResults(databasePath, querySuitePaths, sarifFile, addSnippetsFlag, threadsFlag, verbosityFlag, automationDetailsId, featureEnablement) {
|
async databaseInterpretResults(databasePath, querySuitePaths, sarifFile, addSnippetsFlag, threadsFlag, verbosityFlag, automationDetailsId, featureEnablement) {
|
||||||
const codeqlArgs = [
|
const codeqlArgs = [
|
||||||
|
|
@ -696,7 +696,8 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
||||||
codeqlArgs.push(...querySuitePaths);
|
codeqlArgs.push(...querySuitePaths);
|
||||||
}
|
}
|
||||||
// capture stdout, which contains analysis summaries
|
// capture stdout, which contains analysis summaries
|
||||||
return await runTool(cmd, codeqlArgs);
|
const returnState = await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)(cmd, codeqlArgs, error_matcher_1.errorMatchers);
|
||||||
|
return returnState.stdout;
|
||||||
},
|
},
|
||||||
async databasePrintBaseline(databasePath) {
|
async databasePrintBaseline(databasePath) {
|
||||||
const codeqlArgs = [
|
const codeqlArgs = [
|
||||||
|
|
@ -860,11 +861,16 @@ async function runTool(cmd, args = []) {
|
||||||
const exitCode = await new toolrunner.ToolRunner(cmd, args, {
|
const exitCode = await new toolrunner.ToolRunner(cmd, args, {
|
||||||
listeners: {
|
listeners: {
|
||||||
stdout: (data) => {
|
stdout: (data) => {
|
||||||
output += data.toString();
|
output += data.toString("utf8");
|
||||||
},
|
},
|
||||||
stderr: (data) => {
|
stderr: (data) => {
|
||||||
const toRead = Math.min(maxErrorSize - error.length, data.length);
|
let readStartIndex = 0;
|
||||||
error += data.toString("utf8", 0, toRead);
|
// If the error is too large, then we only take the last 20,000 characters
|
||||||
|
if (data.length - maxErrorSize > 0) {
|
||||||
|
// Eg: if we have 20,000 the start index should be 2.
|
||||||
|
readStartIndex = data.length - maxErrorSize + 1;
|
||||||
|
}
|
||||||
|
error += data.toString("utf8", readStartIndex);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
11
lib/codeql.test.js
generated
11
lib/codeql.test.js
generated
|
|
@ -27,6 +27,7 @@ const fs = __importStar(require("fs"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const toolrunner = __importStar(require("@actions/exec/lib/toolrunner"));
|
const toolrunner = __importStar(require("@actions/exec/lib/toolrunner"));
|
||||||
const toolcache = __importStar(require("@actions/tool-cache"));
|
const toolcache = __importStar(require("@actions/tool-cache"));
|
||||||
|
const safeWhich = __importStar(require("@chrisgavin/safe-which"));
|
||||||
const ava_1 = __importDefault(require("ava"));
|
const ava_1 = __importDefault(require("ava"));
|
||||||
const del_1 = __importDefault(require("del"));
|
const del_1 = __importDefault(require("del"));
|
||||||
const yaml = __importStar(require("js-yaml"));
|
const yaml = __importStar(require("js-yaml"));
|
||||||
|
|
@ -308,6 +309,8 @@ for (const [isFeatureEnabled, toolsInput, shouldToolcacheBeBypassed,] of TOOLCAC
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("2.7.0");
|
sinon.stub(codeqlObject, "getVersion").resolves("2.7.0");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", (0, testing_utils_1.createFeatures)([]));
|
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", (0, testing_utils_1.createFeatures)([]));
|
||||||
t.false(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"), "--sarif-add-query-help should be absent, but it is present");
|
t.false(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"), "--sarif-add-query-help should be absent, but it is present");
|
||||||
});
|
});
|
||||||
|
|
@ -315,6 +318,8 @@ for (const [isFeatureEnabled, toolsInput, shouldToolcacheBeBypassed,] of TOOLCAC
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("2.7.1");
|
sinon.stub(codeqlObject, "getVersion").resolves("2.7.1");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", (0, testing_utils_1.createFeatures)([]));
|
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", (0, testing_utils_1.createFeatures)([]));
|
||||||
t.true(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"), "--sarif-add-query-help should be present, but it is absent");
|
t.true(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"), "--sarif-add-query-help should be present, but it is absent");
|
||||||
});
|
});
|
||||||
|
|
@ -323,6 +328,8 @@ for (const [isFeatureEnabled, toolsInput, shouldToolcacheBeBypassed,] of TOOLCAC
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("2.8.1");
|
sinon.stub(codeqlObject, "getVersion").resolves("2.8.1");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
const thisStubConfig = {
|
const thisStubConfig = {
|
||||||
...stubConfig,
|
...stubConfig,
|
||||||
tempDir,
|
tempDir,
|
||||||
|
|
@ -571,6 +578,8 @@ const injectedConfigMacro = ava_1.default.macro({
|
||||||
// The version of CodeQL is checked separately to determine feature enablement, and does not
|
// The version of CodeQL is checked separately to determine feature enablement, and does not
|
||||||
// otherwise impact this test, so set it to 0.0.0.
|
// otherwise impact this test, so set it to 0.0.0.
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.FileBaselineInformationEnabled]));
|
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.FileBaselineInformationEnabled]));
|
||||||
t.true(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-baseline-file-info"), "--sarif-add-baseline-file-info should be present, but it is absent");
|
t.true(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-baseline-file-info"), "--sarif-add-baseline-file-info should be present, but it is absent");
|
||||||
});
|
});
|
||||||
|
|
@ -581,6 +590,8 @@ const injectedConfigMacro = ava_1.default.macro({
|
||||||
// The version of CodeQL is checked upstream to determine feature enablement, so it does not
|
// The version of CodeQL is checked upstream to determine feature enablement, so it does not
|
||||||
// affect this test.
|
// affect this test.
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", (0, testing_utils_1.createFeatures)([]));
|
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", (0, testing_utils_1.createFeatures)([]));
|
||||||
t.false(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-baseline-file-info"), "--sarif-add-baseline-file-info must be absent, but it is present");
|
t.false(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-baseline-file-info"), "--sarif-add-baseline-file-info must be absent, but it is present");
|
||||||
});
|
});
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
4
lib/error-matcher.js
generated
4
lib/error-matcher.js
generated
|
|
@ -12,6 +12,10 @@ exports.namedMatchersForTesting = {
|
||||||
message: "No code found during the build. Please see:\n" +
|
message: "No code found during the build. Please see:\n" +
|
||||||
"https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/troubleshooting-code-scanning#no-code-found-during-the-build",
|
"https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/troubleshooting-code-scanning#no-code-found-during-the-build",
|
||||||
},
|
},
|
||||||
|
fatalError: {
|
||||||
|
outputRegex: new RegExp("A fatal error occurred"),
|
||||||
|
message: "A fatal error occurred.",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
// we collapse the matches into an array for use in execErrorCatcher
|
// we collapse the matches into an array for use in execErrorCatcher
|
||||||
exports.errorMatchers = Object.values(exports.namedMatchersForTesting);
|
exports.errorMatchers = Object.values(exports.namedMatchersForTesting);
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"error-matcher.js","sourceRoot":"","sources":["../src/error-matcher.ts"],"names":[],"mappings":";;;AAQA,qCAAqC;AACxB,QAAA,uBAAuB,GAAoC;IACtE;;MAEE;IACF,iBAAiB,EAAE;QACjB,QAAQ,EAAE,EAAE;QACZ,WAAW,EAAE,IAAI,MAAM,CAAC,2CAA2C,CAAC;QACpE,OAAO,EACL,+CAA+C;YAC/C,yJAAyJ;KAC5J;CACF,CAAC;AAEF,oEAAoE;AACvD,QAAA,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,+BAAuB,CAAC,CAAC"}
|
{"version":3,"file":"error-matcher.js","sourceRoot":"","sources":["../src/error-matcher.ts"],"names":[],"mappings":";;;AAQA,qCAAqC;AACxB,QAAA,uBAAuB,GAAoC;IACtE;;MAEE;IACF,iBAAiB,EAAE;QACjB,QAAQ,EAAE,EAAE;QACZ,WAAW,EAAE,IAAI,MAAM,CAAC,2CAA2C,CAAC;QACpE,OAAO,EACL,+CAA+C;YAC/C,yJAAyJ;KAC5J;IACD,UAAU,EAAE;QACV,WAAW,EAAE,IAAI,MAAM,CAAC,wBAAwB,CAAC;QACjD,OAAO,EAAE,yBAAyB;KACnC;CACF,CAAC;AAEF,oEAAoE;AACvD,QAAA,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,+BAAuB,CAAC,CAAC"}
|
||||||
3
lib/error-matcher.test.js
generated
3
lib/error-matcher.test.js
generated
|
|
@ -16,6 +16,9 @@ NB We test the regexes for all the matchers against example log output snippets.
|
||||||
2020-09-07T17:39:53.9251124Z [2020-09-07 17:39:53] [ERROR] Spawned process exited abnormally (code 255; tried to run: [/opt/hostedtoolcache/CodeQL/0.0.0-20200630/x64/codeql/javascript/tools/autobuild.sh])
|
2020-09-07T17:39:53.9251124Z [2020-09-07 17:39:53] [ERROR] Spawned process exited abnormally (code 255; tried to run: [/opt/hostedtoolcache/CodeQL/0.0.0-20200630/x64/codeql/javascript/tools/autobuild.sh])
|
||||||
`));
|
`));
|
||||||
});
|
});
|
||||||
|
(0, ava_1.default)("fatalError matches against example log output", async (t) => {
|
||||||
|
t.assert(testErrorMatcher("fatalError", "A fatal error occurred: Could not process query metadata for test-query.ql"));
|
||||||
|
});
|
||||||
function testErrorMatcher(matcherName, logSample) {
|
function testErrorMatcher(matcherName, logSample) {
|
||||||
if (!(matcherName in error_matcher_1.namedMatchersForTesting)) {
|
if (!(matcherName in error_matcher_1.namedMatchersForTesting)) {
|
||||||
throw new Error(`Unknown matcher ${matcherName}`);
|
throw new Error(`Unknown matcher ${matcherName}`);
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"error-matcher.test.js","sourceRoot":"","sources":["../src/error-matcher.test.ts"],"names":[],"mappings":";;;;;AAAA,8CAAuB;AAEvB,mDAA0D;AAE1D;;EAEE;AAEF,IAAA,aAAI,EAAC,6DAA6D,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC9E,CAAC,CAAC,MAAM,CACN,gBAAgB,CACd,mBAAmB,EACnB;;;;;GAKH,CACE,CACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,SAAS,gBAAgB,CAAC,WAAmB,EAAE,SAAiB;IAC9D,IAAI,CAAC,CAAC,WAAW,IAAI,uCAAuB,CAAC,EAAE;QAC7C,MAAM,IAAI,KAAK,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;KACnD;IACD,MAAM,KAAK,GAAG,uCAAuB,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC;IAC/D,IAAI,KAAK,KAAK,SAAS,EAAE;QACvB,MAAM,IAAI,KAAK,CAAC,uBAAuB,WAAW,kBAAkB,CAAC,CAAC;KACvE;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAC/B,CAAC"}
|
{"version":3,"file":"error-matcher.test.js","sourceRoot":"","sources":["../src/error-matcher.test.ts"],"names":[],"mappings":";;;;;AAAA,8CAAuB;AAEvB,mDAA0D;AAE1D;;EAEE;AAEF,IAAA,aAAI,EAAC,6DAA6D,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC9E,CAAC,CAAC,MAAM,CACN,gBAAgB,CACd,mBAAmB,EACnB;;;;;GAKH,CACE,CACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAA,aAAI,EAAC,+CAA+C,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAChE,CAAC,CAAC,MAAM,CACN,gBAAgB,CACd,YAAY,EACZ,4EAA4E,CAC7E,CACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,SAAS,gBAAgB,CAAC,WAAmB,EAAE,SAAiB;IAC9D,IAAI,CAAC,CAAC,WAAW,IAAI,uCAAuB,CAAC,EAAE;QAC7C,MAAM,IAAI,KAAK,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;KACnD;IACD,MAAM,KAAK,GAAG,uCAAuB,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC;IAC/D,IAAI,KAAK,KAAK,SAAS,EAAE;QACvB,MAAM,IAAI,KAAK,CAAC,uBAAuB,WAAW,kBAAkB,CAAC,CAAC;KACvE;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAC/B,CAAC"}
|
||||||
40
lib/toolrunner-error-catcher.js
generated
40
lib/toolrunner-error-catcher.js
generated
|
|
@ -31,7 +31,7 @@ const safeWhich = __importStar(require("@chrisgavin/safe-which"));
|
||||||
* @param args optional arguments for tool. Escaping is handled by the lib.
|
* @param args optional arguments for tool. Escaping is handled by the lib.
|
||||||
* @param matchers defines specific codes and/or regexes that should lead to return of a custom error
|
* @param matchers defines specific codes and/or regexes that should lead to return of a custom error
|
||||||
* @param options optional exec options. See ExecOptions
|
* @param options optional exec options. See ExecOptions
|
||||||
* @returns Promise<number> exit code
|
* @returns ReturnState exit code and stdout output, if applicable
|
||||||
*/
|
*/
|
||||||
async function toolrunnerErrorCatcher(commandLine, args, matchers, options) {
|
async function toolrunnerErrorCatcher(commandLine, args, matchers, options) {
|
||||||
var _a, _b;
|
var _a, _b;
|
||||||
|
|
@ -54,40 +54,36 @@ async function toolrunnerErrorCatcher(commandLine, args, matchers, options) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// we capture the original return code or error so that if no match is found we can duplicate the behavior
|
// we capture the original return code or error so that if no match is found we can duplicate the behavior
|
||||||
let returnState;
|
let exitCode;
|
||||||
try {
|
try {
|
||||||
returnState = await new toolrunner.ToolRunner(await safeWhich.safeWhich(commandLine), args, {
|
exitCode = await new toolrunner.ToolRunner(await safeWhich.safeWhich(commandLine), args, {
|
||||||
...options,
|
...options,
|
||||||
listeners,
|
listeners,
|
||||||
ignoreReturnCode: true, // so we can check for specific codes using the matchers
|
ignoreReturnCode: true, // so we can check for specific codes using the matchers
|
||||||
}).exec();
|
}).exec();
|
||||||
}
|
// if there is a zero return code then we do not apply the matchers
|
||||||
catch (e) {
|
if (exitCode === 0)
|
||||||
returnState = e instanceof Error ? e : new Error(String(e));
|
return { exitCode, stdout };
|
||||||
}
|
if (matchers) {
|
||||||
// if there is a zero return code then we do not apply the matchers
|
for (const matcher of matchers) {
|
||||||
if (returnState === 0)
|
if (matcher.exitCode === exitCode ||
|
||||||
return returnState;
|
((_a = matcher.outputRegex) === null || _a === void 0 ? void 0 : _a.test(stderr)) ||
|
||||||
if (matchers) {
|
((_b = matcher.outputRegex) === null || _b === void 0 ? void 0 : _b.test(stdout))) {
|
||||||
for (const matcher of matchers) {
|
throw new Error(matcher.message);
|
||||||
if (matcher.exitCode === returnState ||
|
}
|
||||||
((_a = matcher.outputRegex) === null || _a === void 0 ? void 0 : _a.test(stderr)) ||
|
|
||||||
((_b = matcher.outputRegex) === null || _b === void 0 ? void 0 : _b.test(stdout))) {
|
|
||||||
throw new Error(matcher.message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (typeof returnState === "number") {
|
|
||||||
// only if we were instructed to ignore the return code do we ever return it non-zero
|
// only if we were instructed to ignore the return code do we ever return it non-zero
|
||||||
if (options === null || options === void 0 ? void 0 : options.ignoreReturnCode) {
|
if (options === null || options === void 0 ? void 0 : options.ignoreReturnCode) {
|
||||||
return returnState;
|
return { exitCode, stdout };
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error(`The process '${commandLine}' failed with exit code ${returnState}`);
|
throw new Error(`The process '${commandLine}' failed with exit code ${exitCode}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
catch (e) {
|
||||||
throw returnState;
|
const error = e instanceof Error ? e : new Error(String(e));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.toolrunnerErrorCatcher = toolrunnerErrorCatcher;
|
exports.toolrunnerErrorCatcher = toolrunnerErrorCatcher;
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"toolrunner-error-catcher.js","sourceRoot":"","sources":["../src/toolrunner-error-catcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AACA,yEAA2D;AAC3D,kEAAoD;AAIpD;;;;;;;;;;GAUG;AACI,KAAK,UAAU,sBAAsB,CAC1C,WAAmB,EACnB,IAAe,EACf,QAAyB,EACzB,OAAwB;;IAExB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAEhB,MAAM,SAAS,GAAG;QAChB,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;;YACvB,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,0CAAE,MAAM,MAAK,SAAS,EAAE;gBAC5C,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;aAChC;QACH,CAAC;QACD,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;;YACvB,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,0CAAE,MAAM,MAAK,SAAS,EAAE;gBAC5C,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;aAChC;QACH,CAAC;KACF,CAAC;IAEF,0GAA0G;IAC1G,IAAI,WAA2B,CAAC;IAChC,IAAI;QACF,WAAW,GAAG,MAAM,IAAI,UAAU,CAAC,UAAU,CAC3C,MAAM,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,EACtC,IAAI,EACJ;YACE,GAAG,OAAO;YACV,SAAS;YACT,gBAAgB,EAAE,IAAI,EAAE,wDAAwD;SACjF,CACF,CAAC,IAAI,EAAE,CAAC;KACV;IAAC,OAAO,CAAC,EAAE;QACV,WAAW,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;KAC7D;IAED,mEAAmE;IACnE,IAAI,WAAW,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAE1C,IAAI,QAAQ,EAAE;QACZ,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC9B,IACE,OAAO,CAAC,QAAQ,KAAK,WAAW;iBAChC,MAAA,OAAO,CAAC,WAAW,0CAAE,IAAI,CAAC,MAAM,CAAC,CAAA;iBACjC,MAAA,OAAO,CAAC,WAAW,0CAAE,IAAI,CAAC,MAAM,CAAC,CAAA,EACjC;gBACA,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;aAClC;SACF;KACF;IAED,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE;QACnC,qFAAqF;QACrF,IAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,EAAE;YAC7B,OAAO,WAAW,CAAC;SACpB;aAAM;YACL,MAAM,IAAI,KAAK,CACb,gBAAgB,WAAW,2BAA2B,WAAW,EAAE,CACpE,CAAC;SACH;KACF;SAAM;QACL,MAAM,WAAW,CAAC;KACnB;AACH,CAAC;AAnED,wDAmEC"}
|
{"version":3,"file":"toolrunner-error-catcher.js","sourceRoot":"","sources":["../src/toolrunner-error-catcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AACA,yEAA2D;AAC3D,kEAAoD;AASpD;;;;;;;;;;GAUG;AACI,KAAK,UAAU,sBAAsB,CAC1C,WAAmB,EACnB,IAAe,EACf,QAAyB,EACzB,OAAwB;;IAExB,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAEhB,MAAM,SAAS,GAAG;QAChB,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;;YACvB,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,0CAAE,MAAM,MAAK,SAAS,EAAE;gBAC5C,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;aAChC;QACH,CAAC;QACD,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;;YACvB,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,SAAS,0CAAE,MAAM,MAAK,SAAS,EAAE;gBAC5C,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;aAChC;QACH,CAAC;KACF,CAAC;IAEF,0GAA0G;IAC1G,IAAI,QAAgB,CAAC;IACrB,IAAI;QACF,QAAQ,GAAG,MAAM,IAAI,UAAU,CAAC,UAAU,CACxC,MAAM,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,EACtC,IAAI,EACJ;YACE,GAAG,OAAO;YACV,SAAS;YACT,gBAAgB,EAAE,IAAI,EAAE,wDAAwD;SACjF,CACF,CAAC,IAAI,EAAE,CAAC;QAET,mEAAmE;QACnE,IAAI,QAAQ,KAAK,CAAC;YAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAEhD,IAAI,QAAQ,EAAE;YACZ,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;gBAC9B,IACE,OAAO,CAAC,QAAQ,KAAK,QAAQ;qBAC7B,MAAA,OAAO,CAAC,WAAW,0CAAE,IAAI,CAAC,MAAM,CAAC,CAAA;qBACjC,MAAA,OAAO,CAAC,WAAW,0CAAE,IAAI,CAAC,MAAM,CAAC,CAAA,EACjC;oBACA,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;iBAClC;aACF;SACF;QAED,qFAAqF;QACrF,IAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,EAAE;YAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;SAC7B;aAAM;YACL,MAAM,IAAI,KAAK,CACb,gBAAgB,WAAW,2BAA2B,QAAQ,EAAE,CACjE,CAAC;SACH;KACF;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,KAAK,CAAC;KACb;AACH,CAAC;AAhED,wDAgEC"}
|
||||||
13
lib/toolrunner-error-catcher.test.js
generated
13
lib/toolrunner-error-catcher.test.js
generated
|
|
@ -33,7 +33,8 @@ const toolrunner_error_catcher_1 = require("./toolrunner-error-catcher");
|
||||||
{ exitCode: 123, outputRegex: new RegExp("foo bar"), message: "error!!!" },
|
{ exitCode: 123, outputRegex: new RegExp("foo bar"), message: "error!!!" },
|
||||||
];
|
];
|
||||||
t.deepEqual(await exec.exec("node", testArgs), 0);
|
t.deepEqual(await exec.exec("node", testArgs), 0);
|
||||||
t.deepEqual(await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)("node", testArgs, matchers), 0);
|
const returnState = await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)("node", testArgs, matchers);
|
||||||
|
t.deepEqual(returnState.exitCode, 0);
|
||||||
});
|
});
|
||||||
(0, ava_1.default)("regex matchers are applied to stdout for non-zero exit code", async (t) => {
|
(0, ava_1.default)("regex matchers are applied to stdout for non-zero exit code", async (t) => {
|
||||||
const testArgs = buildDummyArgs("foo bar\\nblort qux", "", "", 1);
|
const testArgs = buildDummyArgs("foo bar\\nblort qux", "", "", 1);
|
||||||
|
|
@ -116,9 +117,10 @@ const toolrunner_error_catcher_1 = require("./toolrunner-error-catcher");
|
||||||
(0, ava_1.default)("execErrorCatcher respects the ignoreReturnValue option", async (t) => {
|
(0, ava_1.default)("execErrorCatcher respects the ignoreReturnValue option", async (t) => {
|
||||||
const testArgs = buildDummyArgs("standard output", "error output", "", 199);
|
const testArgs = buildDummyArgs("standard output", "error output", "", 199);
|
||||||
await t.throwsAsync((0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)("node", testArgs, [], { ignoreReturnCode: false }), { instanceOf: Error });
|
await t.throwsAsync((0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)("node", testArgs, [], { ignoreReturnCode: false }), { instanceOf: Error });
|
||||||
t.deepEqual(await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)("node", testArgs, [], {
|
const returnState = await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)("node", testArgs, [], {
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true,
|
||||||
}), 199);
|
});
|
||||||
|
t.deepEqual(returnState.exitCode, 199);
|
||||||
});
|
});
|
||||||
(0, ava_1.default)("execErrorCatcher preserves behavior of provided listeners", async (t) => {
|
(0, ava_1.default)("execErrorCatcher preserves behavior of provided listeners", async (t) => {
|
||||||
const stdoutExpected = "standard output";
|
const stdoutExpected = "standard output";
|
||||||
|
|
@ -134,9 +136,10 @@ const toolrunner_error_catcher_1 = require("./toolrunner-error-catcher");
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const testArgs = buildDummyArgs(stdoutExpected, stderrExpected, "", 0);
|
const testArgs = buildDummyArgs(stdoutExpected, stderrExpected, "", 0);
|
||||||
t.deepEqual(await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)("node", testArgs, [], {
|
const returnState = await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)("node", testArgs, [], {
|
||||||
listeners,
|
listeners,
|
||||||
}), 0);
|
});
|
||||||
|
t.deepEqual(returnState.exitCode, 0);
|
||||||
t.deepEqual(stdoutActual, `${stdoutExpected}\n`);
|
t.deepEqual(stdoutActual, `${stdoutExpected}\n`);
|
||||||
t.deepEqual(stderrActual, `${stderrExpected}\n`);
|
t.deepEqual(stderrActual, `${stderrExpected}\n`);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -322,8 +322,6 @@ async function run() {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(error);
|
|
||||||
|
|
||||||
if (error instanceof CodeQLAnalysisError) {
|
if (error instanceof CodeQLAnalysisError) {
|
||||||
const stats = { ...error.queriesStatusReport };
|
const stats = { ...error.queriesStatusReport };
|
||||||
await sendStatusReport(
|
await sendStatusReport(
|
||||||
|
|
@ -398,7 +396,6 @@ async function runWrapper() {
|
||||||
await runPromise;
|
await runPromise;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(`analyze action failed: ${error}`);
|
core.setFailed(`analyze action failed: ${error}`);
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
await checkForTimeout();
|
await checkForTimeout();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import * as path from "path";
|
||||||
|
|
||||||
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
||||||
import * as toolcache from "@actions/tool-cache";
|
import * as toolcache from "@actions/tool-cache";
|
||||||
|
import * as safeWhich from "@chrisgavin/safe-which";
|
||||||
import test, { ExecutionContext } from "ava";
|
import test, { ExecutionContext } from "ava";
|
||||||
import del from "del";
|
import del from "del";
|
||||||
import * as yaml from "js-yaml";
|
import * as yaml from "js-yaml";
|
||||||
|
|
@ -442,6 +443,8 @@ test("databaseInterpretResults() does not set --sarif-add-query-help for 2.7.0",
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("2.7.0");
|
sinon.stub(codeqlObject, "getVersion").resolves("2.7.0");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
await codeqlObject.databaseInterpretResults(
|
await codeqlObject.databaseInterpretResults(
|
||||||
"",
|
"",
|
||||||
[],
|
[],
|
||||||
|
|
@ -462,6 +465,8 @@ test("databaseInterpretResults() sets --sarif-add-query-help for 2.7.1", async (
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("2.7.1");
|
sinon.stub(codeqlObject, "getVersion").resolves("2.7.1");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
await codeqlObject.databaseInterpretResults(
|
await codeqlObject.databaseInterpretResults(
|
||||||
"",
|
"",
|
||||||
[],
|
[],
|
||||||
|
|
@ -483,6 +488,8 @@ test("databaseInitCluster() without injected codescanning config", async (t) =>
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("2.8.1");
|
sinon.stub(codeqlObject, "getVersion").resolves("2.8.1");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
|
|
||||||
const thisStubConfig: Config = {
|
const thisStubConfig: Config = {
|
||||||
...stubConfig,
|
...stubConfig,
|
||||||
|
|
@ -865,6 +872,8 @@ test("databaseInterpretResults() sets --sarif-add-baseline-file-info when featur
|
||||||
// The version of CodeQL is checked separately to determine feature enablement, and does not
|
// The version of CodeQL is checked separately to determine feature enablement, and does not
|
||||||
// otherwise impact this test, so set it to 0.0.0.
|
// otherwise impact this test, so set it to 0.0.0.
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
await codeqlObject.databaseInterpretResults(
|
await codeqlObject.databaseInterpretResults(
|
||||||
"",
|
"",
|
||||||
[],
|
[],
|
||||||
|
|
@ -890,6 +899,8 @@ test("databaseInterpretResults() does not set --sarif-add-baseline-file-info if
|
||||||
// The version of CodeQL is checked upstream to determine feature enablement, so it does not
|
// The version of CodeQL is checked upstream to determine feature enablement, so it does not
|
||||||
// affect this test.
|
// affect this test.
|
||||||
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
||||||
|
// safeWhich throws because of the test CodeQL object.
|
||||||
|
sinon.stub(safeWhich, "safeWhich").resolves("");
|
||||||
await codeqlObject.databaseInterpretResults(
|
await codeqlObject.databaseInterpretResults(
|
||||||
"",
|
"",
|
||||||
[],
|
[],
|
||||||
|
|
|
||||||
|
|
@ -1024,7 +1024,7 @@ async function getCodeQLForCmd(
|
||||||
if (querySuitePath) {
|
if (querySuitePath) {
|
||||||
codeqlArgs.push(querySuitePath);
|
codeqlArgs.push(querySuitePath);
|
||||||
}
|
}
|
||||||
await runTool(cmd, codeqlArgs);
|
await toolrunnerErrorCatcher(cmd, codeqlArgs, errorMatchers);
|
||||||
},
|
},
|
||||||
async databaseInterpretResults(
|
async databaseInterpretResults(
|
||||||
databasePath: string,
|
databasePath: string,
|
||||||
|
|
@ -1067,7 +1067,12 @@ async function getCodeQLForCmd(
|
||||||
codeqlArgs.push(...querySuitePaths);
|
codeqlArgs.push(...querySuitePaths);
|
||||||
}
|
}
|
||||||
// capture stdout, which contains analysis summaries
|
// capture stdout, which contains analysis summaries
|
||||||
return await runTool(cmd, codeqlArgs);
|
const returnState = await toolrunnerErrorCatcher(
|
||||||
|
cmd,
|
||||||
|
codeqlArgs,
|
||||||
|
errorMatchers
|
||||||
|
);
|
||||||
|
return returnState.stdout;
|
||||||
},
|
},
|
||||||
async databasePrintBaseline(databasePath: string): Promise<string> {
|
async databasePrintBaseline(databasePath: string): Promise<string> {
|
||||||
const codeqlArgs = [
|
const codeqlArgs = [
|
||||||
|
|
@ -1271,11 +1276,16 @@ async function runTool(cmd: string, args: string[] = []) {
|
||||||
const exitCode = await new toolrunner.ToolRunner(cmd, args, {
|
const exitCode = await new toolrunner.ToolRunner(cmd, args, {
|
||||||
listeners: {
|
listeners: {
|
||||||
stdout: (data: Buffer) => {
|
stdout: (data: Buffer) => {
|
||||||
output += data.toString();
|
output += data.toString("utf8");
|
||||||
},
|
},
|
||||||
stderr: (data: Buffer) => {
|
stderr: (data: Buffer) => {
|
||||||
const toRead = Math.min(maxErrorSize - error.length, data.length);
|
let readStartIndex = 0;
|
||||||
error += data.toString("utf8", 0, toRead);
|
// If the error is too large, then we only take the last 20,000 characters
|
||||||
|
if (data.length - maxErrorSize > 0) {
|
||||||
|
// Eg: if we have 20,000 the start index should be 2.
|
||||||
|
readStartIndex = data.length - maxErrorSize + 1;
|
||||||
|
}
|
||||||
|
error += data.toString("utf8", readStartIndex);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ignoreReturnCode: true,
|
ignoreReturnCode: true,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,15 @@ test("noSourceCodeFound matches against example javascript output", async (t) =>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("fatalError matches against example log output", async (t) => {
|
||||||
|
t.assert(
|
||||||
|
testErrorMatcher(
|
||||||
|
"fatalError",
|
||||||
|
"A fatal error occurred: Could not process query metadata for test-query.ql"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
function testErrorMatcher(matcherName: string, logSample: string): boolean {
|
function testErrorMatcher(matcherName: string, logSample: string): boolean {
|
||||||
if (!(matcherName in namedMatchersForTesting)) {
|
if (!(matcherName in namedMatchersForTesting)) {
|
||||||
throw new Error(`Unknown matcher ${matcherName}`);
|
throw new Error(`Unknown matcher ${matcherName}`);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@ export const namedMatchersForTesting: { [key: string]: ErrorMatcher } = {
|
||||||
"No code found during the build. Please see:\n" +
|
"No code found during the build. Please see:\n" +
|
||||||
"https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/troubleshooting-code-scanning#no-code-found-during-the-build",
|
"https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/troubleshooting-code-scanning#no-code-found-during-the-build",
|
||||||
},
|
},
|
||||||
|
fatalError: {
|
||||||
|
outputRegex: new RegExp("A fatal error occurred"),
|
||||||
|
message: "A fatal error occurred.",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// we collapse the matches into an array for use in execErrorCatcher
|
// we collapse the matches into an array for use in execErrorCatcher
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ test("matchers are never applied if non-error exit", async (t) => {
|
||||||
|
|
||||||
t.deepEqual(await exec.exec("node", testArgs), 0);
|
t.deepEqual(await exec.exec("node", testArgs), 0);
|
||||||
|
|
||||||
t.deepEqual(await toolrunnerErrorCatcher("node", testArgs, matchers), 0);
|
const returnState = await toolrunnerErrorCatcher("node", testArgs, matchers);
|
||||||
|
t.deepEqual(returnState.exitCode, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("regex matchers are applied to stdout for non-zero exit code", async (t) => {
|
test("regex matchers are applied to stdout for non-zero exit code", async (t) => {
|
||||||
|
|
@ -150,12 +151,11 @@ test("execErrorCatcher respects the ignoreReturnValue option", async (t) => {
|
||||||
{ instanceOf: Error }
|
{ instanceOf: Error }
|
||||||
);
|
);
|
||||||
|
|
||||||
t.deepEqual(
|
const returnState = await toolrunnerErrorCatcher("node", testArgs, [], {
|
||||||
await toolrunnerErrorCatcher("node", testArgs, [], {
|
ignoreReturnCode: true,
|
||||||
ignoreReturnCode: true,
|
});
|
||||||
}),
|
|
||||||
199
|
t.deepEqual(returnState.exitCode, 199);
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("execErrorCatcher preserves behavior of provided listeners", async (t) => {
|
test("execErrorCatcher preserves behavior of provided listeners", async (t) => {
|
||||||
|
|
@ -176,12 +176,10 @@ test("execErrorCatcher preserves behavior of provided listeners", async (t) => {
|
||||||
|
|
||||||
const testArgs = buildDummyArgs(stdoutExpected, stderrExpected, "", 0);
|
const testArgs = buildDummyArgs(stdoutExpected, stderrExpected, "", 0);
|
||||||
|
|
||||||
t.deepEqual(
|
const returnState = await toolrunnerErrorCatcher("node", testArgs, [], {
|
||||||
await toolrunnerErrorCatcher("node", testArgs, [], {
|
listeners,
|
||||||
listeners,
|
});
|
||||||
}),
|
t.deepEqual(returnState.exitCode, 0);
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
t.deepEqual(stdoutActual, `${stdoutExpected}\n`);
|
t.deepEqual(stdoutActual, `${stdoutExpected}\n`);
|
||||||
t.deepEqual(stderrActual, `${stderrExpected}\n`);
|
t.deepEqual(stderrActual, `${stderrExpected}\n`);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,11 @@ import * as safeWhich from "@chrisgavin/safe-which";
|
||||||
|
|
||||||
import { ErrorMatcher } from "./error-matcher";
|
import { ErrorMatcher } from "./error-matcher";
|
||||||
|
|
||||||
|
export interface ReturnState {
|
||||||
|
exitCode: number;
|
||||||
|
stdout: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for toolrunner.Toolrunner which checks for specific return code and/or regex matches in console output.
|
* Wrapper for toolrunner.Toolrunner which checks for specific return code and/or regex matches in console output.
|
||||||
* Output will be streamed to the live console as well as captured for subsequent processing.
|
* Output will be streamed to the live console as well as captured for subsequent processing.
|
||||||
|
|
@ -13,14 +18,14 @@ import { ErrorMatcher } from "./error-matcher";
|
||||||
* @param args optional arguments for tool. Escaping is handled by the lib.
|
* @param args optional arguments for tool. Escaping is handled by the lib.
|
||||||
* @param matchers defines specific codes and/or regexes that should lead to return of a custom error
|
* @param matchers defines specific codes and/or regexes that should lead to return of a custom error
|
||||||
* @param options optional exec options. See ExecOptions
|
* @param options optional exec options. See ExecOptions
|
||||||
* @returns Promise<number> exit code
|
* @returns ReturnState exit code and stdout output, if applicable
|
||||||
*/
|
*/
|
||||||
export async function toolrunnerErrorCatcher(
|
export async function toolrunnerErrorCatcher(
|
||||||
commandLine: string,
|
commandLine: string,
|
||||||
args?: string[],
|
args?: string[],
|
||||||
matchers?: ErrorMatcher[],
|
matchers?: ErrorMatcher[],
|
||||||
options?: im.ExecOptions
|
options?: im.ExecOptions
|
||||||
): Promise<number> {
|
): Promise<ReturnState> {
|
||||||
let stdout = "";
|
let stdout = "";
|
||||||
let stderr = "";
|
let stderr = "";
|
||||||
|
|
||||||
|
|
@ -40,9 +45,9 @@ export async function toolrunnerErrorCatcher(
|
||||||
};
|
};
|
||||||
|
|
||||||
// we capture the original return code or error so that if no match is found we can duplicate the behavior
|
// we capture the original return code or error so that if no match is found we can duplicate the behavior
|
||||||
let returnState: Error | number;
|
let exitCode: number;
|
||||||
try {
|
try {
|
||||||
returnState = await new toolrunner.ToolRunner(
|
exitCode = await new toolrunner.ToolRunner(
|
||||||
await safeWhich.safeWhich(commandLine),
|
await safeWhich.safeWhich(commandLine),
|
||||||
args,
|
args,
|
||||||
{
|
{
|
||||||
|
|
@ -51,35 +56,32 @@ export async function toolrunnerErrorCatcher(
|
||||||
ignoreReturnCode: true, // so we can check for specific codes using the matchers
|
ignoreReturnCode: true, // so we can check for specific codes using the matchers
|
||||||
}
|
}
|
||||||
).exec();
|
).exec();
|
||||||
} catch (e) {
|
|
||||||
returnState = e instanceof Error ? e : new Error(String(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is a zero return code then we do not apply the matchers
|
// if there is a zero return code then we do not apply the matchers
|
||||||
if (returnState === 0) return returnState;
|
if (exitCode === 0) return { exitCode, stdout };
|
||||||
|
|
||||||
if (matchers) {
|
if (matchers) {
|
||||||
for (const matcher of matchers) {
|
for (const matcher of matchers) {
|
||||||
if (
|
if (
|
||||||
matcher.exitCode === returnState ||
|
matcher.exitCode === exitCode ||
|
||||||
matcher.outputRegex?.test(stderr) ||
|
matcher.outputRegex?.test(stderr) ||
|
||||||
matcher.outputRegex?.test(stdout)
|
matcher.outputRegex?.test(stdout)
|
||||||
) {
|
) {
|
||||||
throw new Error(matcher.message);
|
throw new Error(matcher.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof returnState === "number") {
|
|
||||||
// only if we were instructed to ignore the return code do we ever return it non-zero
|
// only if we were instructed to ignore the return code do we ever return it non-zero
|
||||||
if (options?.ignoreReturnCode) {
|
if (options?.ignoreReturnCode) {
|
||||||
return returnState;
|
return { exitCode, stdout };
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The process '${commandLine}' failed with exit code ${returnState}`
|
`The process '${commandLine}' failed with exit code ${exitCode}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e) {
|
||||||
throw returnState;
|
const error = e instanceof Error ? e : new Error(String(e));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue