mirror of
https://github.com/github/codeql-action.git
synced 2026-06-02 11:55:22 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 699d8f2cc5 | |||
| c5297a28a2 | |||
| 8ffeae7d05 | |||
| 164c32a61e | |||
| a134948b87 |
@@ -9,6 +9,10 @@ on:
|
||||
# by other workflows.
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
@@ -24,6 +24,10 @@ on:
|
||||
- cron: '0 5 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
@@ -20,6 +20,10 @@ on:
|
||||
- cron: '0 5 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
@@ -19,6 +19,10 @@ on:
|
||||
- cron: '0 5 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
@@ -10,6 +10,10 @@ on:
|
||||
types: [checks_requested]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
@@ -14,6 +14,10 @@ on:
|
||||
- cron: '0 0 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
@@ -17,6 +17,10 @@ on:
|
||||
- cron: '0 5 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
@@ -18,6 +18,11 @@ on:
|
||||
schedule:
|
||||
- cron: '0 5 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
Generated
+70
-25
@@ -31025,13 +31025,15 @@ var require_brace_expansion = __commonJS({
|
||||
parts.push.apply(parts, p);
|
||||
return parts;
|
||||
}
|
||||
function expandTop(str2) {
|
||||
function expandTop(str2, options) {
|
||||
if (!str2)
|
||||
return [];
|
||||
options = options || {};
|
||||
var max = options.max == null ? Infinity : options.max;
|
||||
if (str2.substr(0, 2) === "{}") {
|
||||
str2 = "\\{\\}" + str2.substr(2);
|
||||
}
|
||||
return expand2(escapeBraces(str2), true).map(unescapeBraces);
|
||||
return expand2(escapeBraces(str2), max, true).map(unescapeBraces);
|
||||
}
|
||||
function embrace(str2) {
|
||||
return "{" + str2 + "}";
|
||||
@@ -31045,7 +31047,7 @@ var require_brace_expansion = __commonJS({
|
||||
function gte6(i, y) {
|
||||
return i >= y;
|
||||
}
|
||||
function expand2(str2, isTop) {
|
||||
function expand2(str2, max, isTop) {
|
||||
var expansions = [];
|
||||
var m = balanced("{", "}", str2);
|
||||
if (!m || /\$$/.test(m.pre)) return [str2];
|
||||
@@ -31056,7 +31058,7 @@ var require_brace_expansion = __commonJS({
|
||||
if (!isSequence && !isOptions) {
|
||||
if (m.post.match(/,(?!,).*\}/)) {
|
||||
str2 = m.pre + "{" + m.body + escClose + m.post;
|
||||
return expand2(str2);
|
||||
return expand2(str2, max, true);
|
||||
}
|
||||
return [str2];
|
||||
}
|
||||
@@ -31066,9 +31068,9 @@ var require_brace_expansion = __commonJS({
|
||||
} else {
|
||||
n = parseCommaParts(m.body);
|
||||
if (n.length === 1) {
|
||||
n = expand2(n[0], false).map(embrace);
|
||||
n = expand2(n[0], max, false).map(embrace);
|
||||
if (n.length === 1) {
|
||||
var post = m.post.length ? expand2(m.post, false) : [""];
|
||||
var post = m.post.length ? expand2(m.post, max, false) : [""];
|
||||
return post.map(function(p) {
|
||||
return m.pre + n[0] + p;
|
||||
});
|
||||
@@ -31076,7 +31078,7 @@ var require_brace_expansion = __commonJS({
|
||||
}
|
||||
}
|
||||
var pre = m.pre;
|
||||
var post = m.post.length ? expand2(m.post, false) : [""];
|
||||
var post = m.post.length ? expand2(m.post, max, false) : [""];
|
||||
var N;
|
||||
if (isSequence) {
|
||||
var x = numeric(n[0]);
|
||||
@@ -31114,11 +31116,11 @@ var require_brace_expansion = __commonJS({
|
||||
}
|
||||
} else {
|
||||
N = concatMap(n, function(el) {
|
||||
return expand2(el, false);
|
||||
return expand2(el, max, false);
|
||||
});
|
||||
}
|
||||
for (var j = 0; j < N.length; j++) {
|
||||
for (var k = 0; k < post.length; k++) {
|
||||
for (var k = 0; k < post.length && expansions.length < max; k++) {
|
||||
var expansion = pre + N[j] + post[k];
|
||||
if (!isTop || isSequence || expansion)
|
||||
expansions.push(expansion);
|
||||
@@ -102244,7 +102246,7 @@ var require_commonjs19 = __commonJS({
|
||||
}
|
||||
const pad = n.some(isPadded);
|
||||
N = [];
|
||||
for (let i = x; test(i, y); i += incr) {
|
||||
for (let i = x; test(i, y) && N.length < max; i += incr) {
|
||||
let c;
|
||||
if (isAlphaSequence) {
|
||||
c = String.fromCharCode(i);
|
||||
@@ -151638,6 +151640,7 @@ async function initActionState({
|
||||
computedConfig,
|
||||
tempDir,
|
||||
codeQLCmd: codeql.getPath(),
|
||||
codeQLMetadata: codeql.getCliMetadata(),
|
||||
gitHubVersion: githubVersion,
|
||||
dbLocation: dbLocationOrDefault(dbLocation, tempDir),
|
||||
debugMode,
|
||||
@@ -153791,19 +153794,29 @@ Details: ${e.stack}` : ""}`
|
||||
);
|
||||
}
|
||||
}
|
||||
async function getCodeQL(cmd) {
|
||||
async function getCodeQL(cmd, cliMetadata) {
|
||||
if (cachedCodeQL === void 0) {
|
||||
cachedCodeQL = await getCodeQLForCmd(cmd, true);
|
||||
cachedCodeQL = await getCodeQLForCmd(cmd, true, cliMetadata);
|
||||
} else {
|
||||
cachedCodeQL.hydrateCliMetadata(cliMetadata);
|
||||
}
|
||||
return cachedCodeQL;
|
||||
}
|
||||
async function getCodeQLForCmd(cmd, checkVersion) {
|
||||
function cacheCodeQlVersionForStatusReports(versionInfo) {
|
||||
if (getCachedCodeQlVersion() === void 0) {
|
||||
cacheCodeQlVersion(versionInfo);
|
||||
}
|
||||
}
|
||||
async function getCodeQLForCmd(cmd, checkVersion, initialCliMetadata) {
|
||||
const cliMetadata = { codeQLCmd: cmd };
|
||||
let cachedVersion;
|
||||
let cachedUnfilteredBetterResolveLanguages;
|
||||
const codeql = {
|
||||
getPath() {
|
||||
return cmd;
|
||||
},
|
||||
async getVersion() {
|
||||
let result = getCachedCodeQlVersion();
|
||||
let result = cachedVersion;
|
||||
if (result === void 0) {
|
||||
const output = await runCli(cmd, ["version", "--format=json"], {
|
||||
noStreamStdout: true
|
||||
@@ -153815,12 +153828,17 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
||||
`Invalid JSON output from \`version --format=json\`: ${output}`
|
||||
);
|
||||
}
|
||||
cacheCodeQlVersion(result);
|
||||
cachedVersion = result;
|
||||
}
|
||||
cacheCodeQlVersionForStatusReports(result);
|
||||
return result;
|
||||
},
|
||||
async printVersion() {
|
||||
await runCli(cmd, ["version", "--format=json"]);
|
||||
const version = await this.getVersion();
|
||||
process.stdout.write(`[command]${cmd} version --format=json
|
||||
`);
|
||||
process.stdout.write(`${JSON.stringify(version)}
|
||||
`);
|
||||
},
|
||||
async supportsFeature(feature) {
|
||||
return isSupportedToolsFeature(await this.getVersion(), feature);
|
||||
@@ -153990,6 +154008,9 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
||||
async betterResolveLanguages({
|
||||
filterToLanguagesWithQueries
|
||||
} = { filterToLanguagesWithQueries: false }) {
|
||||
if (!filterToLanguagesWithQueries && cachedUnfilteredBetterResolveLanguages) {
|
||||
return cachedUnfilteredBetterResolveLanguages;
|
||||
}
|
||||
const codeqlArgs = [
|
||||
"resolve",
|
||||
"languages",
|
||||
@@ -154001,7 +154022,11 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
||||
];
|
||||
const output = await runCli(cmd, codeqlArgs);
|
||||
try {
|
||||
return JSON.parse(output);
|
||||
const result = JSON.parse(output);
|
||||
if (!filterToLanguagesWithQueries) {
|
||||
cachedUnfilteredBetterResolveLanguages = result;
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unexpected output from codeql resolve languages with --format=betterjson: ${e}`
|
||||
@@ -154160,6 +154185,10 @@ ${output}`
|
||||
await new toolrunner3.ToolRunner(cmd, args).exec();
|
||||
},
|
||||
async resolveExtractor(language) {
|
||||
const cachedExtractorPath = cliMetadata.extractorPaths?.[language];
|
||||
if (cachedExtractorPath !== void 0) {
|
||||
return cachedExtractorPath;
|
||||
}
|
||||
let extractorPath = "";
|
||||
await new toolrunner3.ToolRunner(
|
||||
cmd,
|
||||
@@ -154183,7 +154212,10 @@ ${output}`
|
||||
}
|
||||
}
|
||||
).exec();
|
||||
return JSON.parse(extractorPath);
|
||||
const resolvedExtractorPath = JSON.parse(extractorPath);
|
||||
cliMetadata.extractorPaths ??= {};
|
||||
cliMetadata.extractorPaths[language] = resolvedExtractorPath;
|
||||
return resolvedExtractorPath;
|
||||
},
|
||||
async resolveQueriesStartingPacks(queries) {
|
||||
const codeqlArgs = [
|
||||
@@ -154236,8 +154268,21 @@ ${output}`
|
||||
args.push("--sarif-merge-runs-from-equal-category");
|
||||
}
|
||||
await runCli(cmd, args);
|
||||
},
|
||||
getCliMetadata() {
|
||||
return cliMetadata;
|
||||
},
|
||||
hydrateCliMetadata(metadata) {
|
||||
if (metadata?.codeQLCmd !== cliMetadata.codeQLCmd) {
|
||||
return;
|
||||
}
|
||||
cliMetadata.extractorPaths = {
|
||||
...metadata.extractorPaths,
|
||||
...cliMetadata.extractorPaths
|
||||
};
|
||||
}
|
||||
};
|
||||
codeql.hydrateCliMetadata(initialCliMetadata);
|
||||
if (checkVersion && !await codeQlVersionAtLeast(codeql, CODEQL_MINIMUM_VERSION)) {
|
||||
throw new ConfigurationError(
|
||||
`Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${(await codeql.getVersion()).version}`
|
||||
@@ -154422,7 +154467,7 @@ async function setupCppAutobuild(codeql, logger) {
|
||||
}
|
||||
async function runAutobuild(config, language, logger) {
|
||||
logger.startGroup(`Attempting to automatically build ${language} code`);
|
||||
const codeQL = await getCodeQL(config.codeQLCmd);
|
||||
const codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
if (language === "cpp" /* cpp */) {
|
||||
await setupCppAutobuild(codeQL, logger);
|
||||
}
|
||||
@@ -157006,7 +157051,7 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo
|
||||
let tempDir = getTemporaryDirectory();
|
||||
const config = await getConfig(tempDir, logger);
|
||||
if (config !== void 0) {
|
||||
codeQL = await getCodeQL(config.codeQLCmd);
|
||||
codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
tempDir = config.tempDir;
|
||||
} else {
|
||||
logger.info(
|
||||
@@ -157740,7 +157785,7 @@ async function run(startedAt) {
|
||||
"Config file could not be found at expected location. Has the 'init' action been called?"
|
||||
);
|
||||
}
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
if (hasBadExpectErrorInput()) {
|
||||
throw new ConfigurationError(
|
||||
"`expect-error` input parameter is for internal use only. It should only be set by codeql-action or a fork."
|
||||
@@ -158509,7 +158554,7 @@ async function runWrapper2() {
|
||||
logger
|
||||
);
|
||||
if (config !== void 0) {
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
const version = await codeql.getVersion();
|
||||
await uploadCombinedSarifArtifacts(
|
||||
logger,
|
||||
@@ -158590,7 +158635,7 @@ async function run2(startedAt) {
|
||||
"Config file could not be found at expected location. Has the 'init' action been called?"
|
||||
);
|
||||
}
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
languages = await determineAutobuildLanguages(codeql, config, logger);
|
||||
if (languages !== void 0) {
|
||||
const workingDirectory = getOptionalInput("working-directory");
|
||||
@@ -159522,7 +159567,7 @@ async function prepareFailedSarif(logger, features, config) {
|
||||
}
|
||||
async function generateFailedSarif(features, config, category, checkoutPath, sarifFile) {
|
||||
const databasePath = config.dbLocation;
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
if (sarifFile === void 0) {
|
||||
sarifFile = "../codeql-failed-run.sarif";
|
||||
}
|
||||
@@ -159788,7 +159833,7 @@ async function run4(startedAt) {
|
||||
"Debugging artifacts are unavailable since the 'init' Action failed before it could produce any."
|
||||
);
|
||||
} else {
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
uploadFailedSarifResult = await uploadFailureInfo(
|
||||
tryUploadAllAvailableDebugArtifacts,
|
||||
printDebugLogs,
|
||||
|
||||
Generated
+9
-9
@@ -3795,9 +3795,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
|
||||
"integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
@@ -5122,9 +5122,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import-x/node_modules/brace-expansion": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -6078,9 +6078,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/brace-expansion": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
|
||||
@@ -38,7 +38,7 @@ export async function runWrapper() {
|
||||
logger,
|
||||
);
|
||||
if (config !== undefined) {
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
const version = await codeql.getVersion();
|
||||
await debugArtifacts.uploadCombinedSarifArtifacts(
|
||||
logger,
|
||||
|
||||
@@ -256,7 +256,7 @@ async function run(startedAt: Date) {
|
||||
);
|
||||
}
|
||||
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
|
||||
if (hasBadExpectErrorInput()) {
|
||||
throw new util.ConfigurationError(
|
||||
|
||||
@@ -101,7 +101,7 @@ async function run(startedAt: Date) {
|
||||
);
|
||||
}
|
||||
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
|
||||
languages = await determineAutobuildLanguages(codeql, config, logger);
|
||||
if (languages !== undefined) {
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ export async function runAutobuild(
|
||||
logger: Logger,
|
||||
) {
|
||||
logger.startGroup(`Attempting to automatically build ${language} code`);
|
||||
const codeQL = await getCodeQL(config.codeQLCmd);
|
||||
const codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
if (language === BuiltInLanguage.cpp) {
|
||||
await setupCppAutobuild(codeQL, logger);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import { ExecOptions } from "@actions/exec";
|
||||
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
||||
@@ -123,6 +124,166 @@ async function stubCodeql(): Promise<codeql.CodeQL> {
|
||||
return codeqlObject;
|
||||
}
|
||||
|
||||
function stubSuccessfulToolRunner(
|
||||
stdoutForArgs: (args: string[]) => string | undefined,
|
||||
): sinon.SinonStub<any[], toolrunner.ToolRunner> {
|
||||
const runnerConstructorStub = sinon.stub(
|
||||
toolrunner,
|
||||
"ToolRunner",
|
||||
) as sinon.SinonStub<any[], toolrunner.ToolRunner>;
|
||||
|
||||
runnerConstructorStub.callsFake((_cmd, args, options: ExecOptions) => {
|
||||
return {
|
||||
exec: async () => {
|
||||
const stdout = stdoutForArgs(args as string[]);
|
||||
if (stdout !== undefined) {
|
||||
options.listeners?.stdout?.(Buffer.from(stdout));
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
} as toolrunner.ToolRunner;
|
||||
});
|
||||
|
||||
return runnerConstructorStub;
|
||||
}
|
||||
|
||||
test.serial("getVersion and printVersion share cached version", async (t) => {
|
||||
const version = { version: "2.30.0" };
|
||||
let versionCalls = 0;
|
||||
stubSuccessfulToolRunner((args) => {
|
||||
if (args.join(" ") === "version --format=json") {
|
||||
versionCalls++;
|
||||
return JSON.stringify(version);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||
|
||||
t.deepEqual(await codeqlObject.getVersion(), version);
|
||||
await codeqlObject.printVersion();
|
||||
|
||||
t.is(versionCalls, 1);
|
||||
});
|
||||
|
||||
test.serial(
|
||||
"betterResolveLanguages caches only the unfiltered result",
|
||||
async (t) => {
|
||||
const unfilteredLanguages = {
|
||||
aliases: { typescript: BuiltInLanguage.javascript },
|
||||
extractors: {
|
||||
html: [{ extractor_root: "/html" }],
|
||||
javascript: [{ extractor_root: "/javascript" }],
|
||||
},
|
||||
};
|
||||
const filteredLanguages = {
|
||||
aliases: { typescript: BuiltInLanguage.javascript },
|
||||
extractors: {
|
||||
javascript: [{ extractor_root: "/javascript" }],
|
||||
},
|
||||
};
|
||||
|
||||
let unfilteredCalls = 0;
|
||||
let filteredCalls = 0;
|
||||
stubSuccessfulToolRunner((args) => {
|
||||
if (args[0] === "resolve" && args[1] === "languages") {
|
||||
if (args.includes("--filter-to-languages-with-queries")) {
|
||||
filteredCalls++;
|
||||
return JSON.stringify(filteredLanguages);
|
||||
}
|
||||
unfilteredCalls++;
|
||||
return JSON.stringify(unfilteredLanguages);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||
|
||||
t.deepEqual(
|
||||
await codeqlObject.betterResolveLanguages(),
|
||||
unfilteredLanguages,
|
||||
);
|
||||
t.deepEqual(
|
||||
await codeqlObject.betterResolveLanguages(),
|
||||
unfilteredLanguages,
|
||||
);
|
||||
t.deepEqual(
|
||||
await codeqlObject.betterResolveLanguages({
|
||||
filterToLanguagesWithQueries: true,
|
||||
}),
|
||||
filteredLanguages,
|
||||
);
|
||||
t.deepEqual(
|
||||
await codeqlObject.betterResolveLanguages({
|
||||
filterToLanguagesWithQueries: true,
|
||||
}),
|
||||
filteredLanguages,
|
||||
);
|
||||
|
||||
// The unfiltered result is cached after the first call; the filtered
|
||||
// variant is not cached because nothing reuses it.
|
||||
t.is(unfilteredCalls, 1);
|
||||
t.is(filteredCalls, 2);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial("resolveExtractor caches its result per language", async (t) => {
|
||||
await util.withTmpDir(async (tempDir) => {
|
||||
const extractorRoot = path.join(tempDir, "javascript");
|
||||
fs.mkdirSync(path.join(extractorRoot, "tools"), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(extractorRoot, "tools", "tracing-config.lua"),
|
||||
"",
|
||||
);
|
||||
|
||||
let resolveExtractorCalls = 0;
|
||||
stubSuccessfulToolRunner((args) => {
|
||||
if (args[0] === "resolve" && args[1] === "extractor") {
|
||||
resolveExtractorCalls++;
|
||||
return JSON.stringify(extractorRoot);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||
|
||||
t.is(
|
||||
await codeqlObject.resolveExtractor(BuiltInLanguage.javascript),
|
||||
extractorRoot,
|
||||
);
|
||||
t.is(
|
||||
await codeqlObject.resolveExtractor(BuiltInLanguage.javascript),
|
||||
extractorRoot,
|
||||
);
|
||||
t.true(await codeqlObject.isTracedLanguage(BuiltInLanguage.javascript));
|
||||
t.is(resolveExtractorCalls, 1);
|
||||
});
|
||||
});
|
||||
|
||||
test.serial(
|
||||
"hydrateCliMetadata seeds the cache from persisted metadata",
|
||||
async (t) => {
|
||||
let cliCalls = 0;
|
||||
stubSuccessfulToolRunner((_args) => {
|
||||
cliCalls++;
|
||||
return "{}";
|
||||
});
|
||||
|
||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||
|
||||
codeqlObject.hydrateCliMetadata({
|
||||
codeQLCmd: "codeql-for-testing",
|
||||
extractorPaths: { javascript: "/javascript" },
|
||||
});
|
||||
|
||||
t.is(
|
||||
await codeqlObject.resolveExtractor(BuiltInLanguage.javascript),
|
||||
"/javascript",
|
||||
);
|
||||
t.is(cliCalls, 0);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"downloads and caches explicitly requested bundles that aren't in the toolcache",
|
||||
async (t) => {
|
||||
|
||||
+87
-13
@@ -218,6 +218,10 @@ export interface CodeQL {
|
||||
outputFile: string,
|
||||
options: { mergeRunsFromEqualCategory?: boolean },
|
||||
): Promise<void>;
|
||||
/** Return cacheable metadata gathered from the CodeQL CLI. */
|
||||
getCliMetadata(): CodeQLCliMetadata;
|
||||
/** Hydrate the CodeQL wrapper with cacheable metadata gathered earlier in the job. */
|
||||
hydrateCliMetadata(metadata: CodeQLCliMetadata | undefined): void;
|
||||
}
|
||||
|
||||
export interface VersionInfo {
|
||||
@@ -247,12 +251,10 @@ export interface BetterResolveLanguagesOutput {
|
||||
[alias: string]: string;
|
||||
};
|
||||
extractors: {
|
||||
[language: string]: [
|
||||
{
|
||||
extractor_root: string;
|
||||
extractor_options?: any;
|
||||
},
|
||||
];
|
||||
[language: string]: Array<{
|
||||
extractor_root: string;
|
||||
extractor_options?: any;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -264,6 +266,11 @@ export interface ResolveBuildEnvironmentOutput {
|
||||
};
|
||||
}
|
||||
|
||||
export interface CodeQLCliMetadata {
|
||||
codeQLCmd: string;
|
||||
extractorPaths?: { [language: string]: string };
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the CodeQL object, and is populated by `setupCodeQL` or `getCodeQL`.
|
||||
*/
|
||||
@@ -392,9 +399,14 @@ export async function setupCodeQL(
|
||||
/**
|
||||
* Use the CodeQL executable located at the given path.
|
||||
*/
|
||||
export async function getCodeQL(cmd: string): Promise<CodeQL> {
|
||||
export async function getCodeQL(
|
||||
cmd: string,
|
||||
cliMetadata?: CodeQLCliMetadata,
|
||||
): Promise<CodeQL> {
|
||||
if (cachedCodeQL === undefined) {
|
||||
cachedCodeQL = await getCodeQLForCmd(cmd, true);
|
||||
cachedCodeQL = await getCodeQLForCmd(cmd, true, cliMetadata);
|
||||
} else {
|
||||
cachedCodeQL.hydrateCliMetadata(cliMetadata);
|
||||
}
|
||||
return cachedCodeQL;
|
||||
}
|
||||
@@ -492,6 +504,14 @@ export function createStubCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
|
||||
),
|
||||
resolveDatabase: resolveFunction(partialCodeql, "resolveDatabase"),
|
||||
mergeResults: resolveFunction(partialCodeql, "mergeResults"),
|
||||
getCliMetadata: resolveFunction(partialCodeql, "getCliMetadata", () => ({
|
||||
codeQLCmd: partialCodeql.getPath?.() ?? "/tmp/dummy-path",
|
||||
})),
|
||||
hydrateCliMetadata: resolveFunction(
|
||||
partialCodeql,
|
||||
"hydrateCliMetadata",
|
||||
() => {},
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -506,6 +526,12 @@ export async function getCodeQLForTesting(
|
||||
return getCodeQLForCmd(cmd, false);
|
||||
}
|
||||
|
||||
function cacheCodeQlVersionForStatusReports(versionInfo: VersionInfo): void {
|
||||
if (util.getCachedCodeQlVersion() === undefined) {
|
||||
util.cacheCodeQlVersion(versionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a CodeQL object for CodeQL CLI access.
|
||||
*
|
||||
@@ -517,13 +543,24 @@ export async function getCodeQLForTesting(
|
||||
async function getCodeQLForCmd(
|
||||
cmd: string,
|
||||
checkVersion: boolean,
|
||||
initialCliMetadata?: CodeQLCliMetadata,
|
||||
): Promise<CodeQL> {
|
||||
// Metadata persisted across the init/autobuild/analyze steps. Only extractor
|
||||
// paths are reused by a later step, so that's all this holds.
|
||||
const cliMetadata: CodeQLCliMetadata = { codeQLCmd: cmd };
|
||||
// In-process-only caches. These aren't persisted because no later step reuses
|
||||
// them: the CLI version always matches across steps, and `resolve languages`
|
||||
// is only re-read within a single step.
|
||||
let cachedVersion: VersionInfo | undefined;
|
||||
let cachedUnfilteredBetterResolveLanguages:
|
||||
| BetterResolveLanguagesOutput
|
||||
| undefined;
|
||||
const codeql: CodeQL = {
|
||||
getPath() {
|
||||
return cmd;
|
||||
},
|
||||
async getVersion() {
|
||||
let result = util.getCachedCodeQlVersion();
|
||||
let result = cachedVersion;
|
||||
if (result === undefined) {
|
||||
const output = await runCli(cmd, ["version", "--format=json"], {
|
||||
noStreamStdout: true,
|
||||
@@ -535,12 +572,15 @@ async function getCodeQLForCmd(
|
||||
`Invalid JSON output from \`version --format=json\`: ${output}`,
|
||||
);
|
||||
}
|
||||
util.cacheCodeQlVersion(result);
|
||||
cachedVersion = result;
|
||||
}
|
||||
cacheCodeQlVersionForStatusReports(result);
|
||||
return result;
|
||||
},
|
||||
async printVersion() {
|
||||
await runCli(cmd, ["version", "--format=json"]);
|
||||
const version = await this.getVersion();
|
||||
process.stdout.write(`[command]${cmd} version --format=json\n`);
|
||||
process.stdout.write(`${JSON.stringify(version)}\n`);
|
||||
},
|
||||
async supportsFeature(feature: ToolsFeature) {
|
||||
return isSupportedToolsFeature(await this.getVersion(), feature);
|
||||
@@ -758,6 +798,13 @@ async function getCodeQLForCmd(
|
||||
filterToLanguagesWithQueries: boolean;
|
||||
} = { filterToLanguagesWithQueries: false },
|
||||
) {
|
||||
if (
|
||||
!filterToLanguagesWithQueries &&
|
||||
cachedUnfilteredBetterResolveLanguages
|
||||
) {
|
||||
return cachedUnfilteredBetterResolveLanguages;
|
||||
}
|
||||
|
||||
const codeqlArgs = [
|
||||
"resolve",
|
||||
"languages",
|
||||
@@ -772,7 +819,11 @@ async function getCodeQLForCmd(
|
||||
const output = await runCli(cmd, codeqlArgs);
|
||||
|
||||
try {
|
||||
return JSON.parse(output) as BetterResolveLanguagesOutput;
|
||||
const result = JSON.parse(output) as BetterResolveLanguagesOutput;
|
||||
if (!filterToLanguagesWithQueries) {
|
||||
cachedUnfilteredBetterResolveLanguages = result;
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unexpected output from codeql resolve languages with --format=betterjson: ${e}`,
|
||||
@@ -968,6 +1019,11 @@ async function getCodeQLForCmd(
|
||||
await new toolrunner.ToolRunner(cmd, args).exec();
|
||||
},
|
||||
async resolveExtractor(language: Language): Promise<string> {
|
||||
const cachedExtractorPath = cliMetadata.extractorPaths?.[language];
|
||||
if (cachedExtractorPath !== undefined) {
|
||||
return cachedExtractorPath;
|
||||
}
|
||||
|
||||
// Request it using `format=json` so we don't need to strip the trailing new line generated by
|
||||
// the CLI.
|
||||
let extractorPath = "";
|
||||
@@ -993,7 +1049,10 @@ async function getCodeQLForCmd(
|
||||
},
|
||||
},
|
||||
).exec();
|
||||
return JSON.parse(extractorPath) as string;
|
||||
const resolvedExtractorPath = JSON.parse(extractorPath) as string;
|
||||
cliMetadata.extractorPaths ??= {};
|
||||
cliMetadata.extractorPaths[language] = resolvedExtractorPath;
|
||||
return resolvedExtractorPath;
|
||||
},
|
||||
async resolveQueriesStartingPacks(queries: string[]): Promise<string[]> {
|
||||
const codeqlArgs = [
|
||||
@@ -1058,7 +1117,22 @@ async function getCodeQLForCmd(
|
||||
|
||||
await runCli(cmd, args);
|
||||
},
|
||||
getCliMetadata() {
|
||||
return cliMetadata;
|
||||
},
|
||||
hydrateCliMetadata(metadata: CodeQLCliMetadata | undefined): void {
|
||||
if (metadata?.codeQLCmd !== cliMetadata.codeQLCmd) {
|
||||
return;
|
||||
}
|
||||
|
||||
cliMetadata.extractorPaths = {
|
||||
...metadata.extractorPaths,
|
||||
...cliMetadata.extractorPaths,
|
||||
};
|
||||
},
|
||||
};
|
||||
// Seed the cache with any metadata persisted by an earlier step.
|
||||
codeql.hydrateCliMetadata(initialCliMetadata);
|
||||
// To ensure that status reports include the CodeQL CLI version wherever
|
||||
// possible, we want to call getVersion(), which populates the version value
|
||||
// used by status reporting, at the earliest opportunity. But invoking
|
||||
|
||||
+6
-1
@@ -19,7 +19,7 @@ import {
|
||||
} from "./analyses";
|
||||
import * as api from "./api-client";
|
||||
import { CachingKind, getCachingKind } from "./caching-utils";
|
||||
import { type CodeQL } from "./codeql";
|
||||
import { type CodeQL, type CodeQLCliMetadata } from "./codeql";
|
||||
import {
|
||||
calculateAugmentation,
|
||||
ExcludeQueryFilter,
|
||||
@@ -177,6 +177,10 @@ export interface Config {
|
||||
* Path of the CodeQL executable.
|
||||
*/
|
||||
codeQLCmd: string;
|
||||
/**
|
||||
* Cacheable metadata gathered from the CodeQL CLI while initializing the workflow.
|
||||
*/
|
||||
codeQLMetadata?: CodeQLCliMetadata;
|
||||
/**
|
||||
* Version of GitHub we are talking to.
|
||||
*/
|
||||
@@ -561,6 +565,7 @@ export async function initActionState(
|
||||
computedConfig,
|
||||
tempDir,
|
||||
codeQLCmd: codeql.getPath(),
|
||||
codeQLMetadata: codeql.getCliMetadata(),
|
||||
gitHubVersion: githubVersion,
|
||||
dbLocation: dbLocationOrDefault(dbLocation, tempDir),
|
||||
debugMode,
|
||||
|
||||
@@ -163,7 +163,7 @@ async function generateFailedSarif(
|
||||
sarifFile?: string,
|
||||
) {
|
||||
const databasePath = config.dbLocation;
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
|
||||
// Set the filename for the SARIF file if not already set.
|
||||
if (sarifFile === undefined) {
|
||||
|
||||
@@ -75,7 +75,7 @@ async function run(startedAt: Date) {
|
||||
"Debugging artifacts are unavailable since the 'init' Action failed before it could produce any.",
|
||||
);
|
||||
} else {
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
|
||||
uploadFailedSarifResult = await initActionPostHelper.uploadFailureInfo(
|
||||
debugArtifacts.tryUploadAllAvailableDebugArtifacts,
|
||||
|
||||
@@ -560,7 +560,7 @@ export function mockBundleDownloadApi({
|
||||
}
|
||||
|
||||
export function createTestConfig(overrides: Partial<Config>): Config {
|
||||
return Object.assign(
|
||||
const config = Object.assign(
|
||||
{},
|
||||
{
|
||||
version: getActionVersion(),
|
||||
@@ -590,6 +590,8 @@ export function createTestConfig(overrides: Partial<Config>): Config {
|
||||
} satisfies Config,
|
||||
overrides,
|
||||
);
|
||||
config.codeQLMetadata ??= { codeQLCmd: config.codeQLCmd };
|
||||
return config;
|
||||
}
|
||||
|
||||
export function makeTestToken(length: number = 36) {
|
||||
|
||||
+1
-1
@@ -140,7 +140,7 @@ async function combineSarifFilesUsingCLI(
|
||||
|
||||
const config = await getConfig(tempDir, logger);
|
||||
if (config !== undefined) {
|
||||
codeQL = await getCodeQL(config.codeQLCmd);
|
||||
codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||
tempDir = config.tempDir;
|
||||
} else {
|
||||
logger.info(
|
||||
|
||||
Reference in New Issue
Block a user