Merge pull request #1540 from cklin/expect-discarded-cache
Set --expect-discarded-cache option
This commit is contained in:
commit
3dde1f3512
12 changed files with 394 additions and 55 deletions
32
lib/analyze.js
generated
32
lib/analyze.js
generated
|
|
@ -126,6 +126,7 @@ async function finalizeDatabaseCreation(config, threadsFlag, memoryFlag, logger)
|
|||
async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag, automationDetailsId, config, logger, featureEnablement) {
|
||||
const statusReport = {};
|
||||
const codeql = await (0, codeql_1.getCodeQL)(config.codeQLCmd);
|
||||
const queryFlags = [memoryFlag, threadsFlag];
|
||||
await util.logCodeScanningConfigInCli(codeql, featureEnablement, logger);
|
||||
for (const language of config.languages) {
|
||||
const queries = config.queries[language];
|
||||
|
|
@ -140,7 +141,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||
// another to interpret the results.
|
||||
logger.startGroup(`Running queries for ${language}`);
|
||||
const startTimeBuiltIn = new Date().getTime();
|
||||
await runQueryGroup(language, "all", undefined, undefined);
|
||||
await runQueryGroup(language, "all", undefined, undefined, true);
|
||||
// TODO should not be using `builtin` here. We should be using `all` instead.
|
||||
// The status report does not support `all` yet.
|
||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||
|
|
@ -164,24 +165,29 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||
!hasPackWithCustomQueries) {
|
||||
throw new Error(`Unable to analyze ${language} as no queries were selected for this language`);
|
||||
}
|
||||
const customQueryIndices = [];
|
||||
for (let i = 0; i < queries.custom.length; ++i) {
|
||||
if (queries.custom[i].queries.length > 0) {
|
||||
customQueryIndices.push(i);
|
||||
}
|
||||
}
|
||||
logger.startGroup(`Running queries for ${language}`);
|
||||
const querySuitePaths = [];
|
||||
if (queries["builtin"].length > 0) {
|
||||
if (queries.builtin.length > 0) {
|
||||
const startTimeBuiltIn = new Date().getTime();
|
||||
querySuitePaths.push((await runQueryGroup(language, "builtin", createQuerySuiteContents(queries["builtin"], queryFilters), undefined)));
|
||||
querySuitePaths.push((await runQueryGroup(language, "builtin", createQuerySuiteContents(queries.builtin, queryFilters), undefined, customQueryIndices.length === 0 && packsWithVersion.length === 0)));
|
||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||
new Date().getTime() - startTimeBuiltIn;
|
||||
}
|
||||
const startTimeCustom = new Date().getTime();
|
||||
let ranCustom = false;
|
||||
for (let i = 0; i < queries["custom"].length; ++i) {
|
||||
if (queries["custom"][i].queries.length > 0) {
|
||||
querySuitePaths.push((await runQueryGroup(language, `custom-${i}`, createQuerySuiteContents(queries["custom"][i].queries, queryFilters), queries["custom"][i].searchPath)));
|
||||
ranCustom = true;
|
||||
}
|
||||
for (const i of customQueryIndices) {
|
||||
querySuitePaths.push((await runQueryGroup(language, `custom-${i}`, createQuerySuiteContents(queries.custom[i].queries, queryFilters), queries.custom[i].searchPath, i === customQueryIndices[customQueryIndices.length - 1] &&
|
||||
packsWithVersion.length === 0)));
|
||||
ranCustom = true;
|
||||
}
|
||||
if (packsWithVersion.length > 0) {
|
||||
querySuitePaths.push(await runQueryPacks(language, "packs", packsWithVersion, queryFilters));
|
||||
querySuitePaths.push(await runQueryPacks(language, "packs", packsWithVersion, queryFilters, true));
|
||||
ranCustom = true;
|
||||
}
|
||||
if (ranCustom) {
|
||||
|
|
@ -218,7 +224,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
return await codeql.databasePrintBaseline(databasePath);
|
||||
}
|
||||
async function runQueryGroup(language, type, querySuiteContents, searchPath) {
|
||||
async function runQueryGroup(language, type, querySuiteContents, searchPath, optimizeForLastQueryRun) {
|
||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
// Pass the queries to codeql using a file instead of using the command
|
||||
// line to avoid command line length restrictions, particularly on windows.
|
||||
|
|
@ -229,11 +235,11 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||
fs.writeFileSync(querySuitePath, querySuiteContents);
|
||||
logger.debug(`Query suite file for ${language}-${type}...\n${querySuiteContents}`);
|
||||
}
|
||||
await codeql.databaseRunQueries(databasePath, searchPath, querySuitePath, memoryFlag, threadsFlag);
|
||||
await codeql.databaseRunQueries(databasePath, searchPath, querySuitePath, queryFlags, optimizeForLastQueryRun);
|
||||
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
||||
return querySuitePath;
|
||||
}
|
||||
async function runQueryPacks(language, type, packs, queryFilters) {
|
||||
async function runQueryPacks(language, type, packs, queryFilters, optimizeForLastQueryRun) {
|
||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
for (const pack of packs) {
|
||||
logger.debug(`Running query pack for ${language}-${type}: ${pack}`);
|
||||
|
|
@ -243,7 +249,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||
const querySuitePath = `${databasePath}-queries-${type}.qls`;
|
||||
fs.writeFileSync(querySuitePath, yaml.dump(querySuite));
|
||||
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
||||
await codeql.databaseRunQueries(databasePath, undefined, querySuitePath, memoryFlag, threadsFlag);
|
||||
await codeql.databaseRunQueries(databasePath, undefined, querySuitePath, queryFlags, optimizeForLastQueryRun);
|
||||
return querySuitePath;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
122
lib/analyze.test.js
generated
122
lib/analyze.test.js
generated
|
|
@ -30,8 +30,10 @@ const fs = __importStar(require("fs"));
|
|||
const path = __importStar(require("path"));
|
||||
const ava_1 = __importDefault(require("ava"));
|
||||
const yaml = __importStar(require("js-yaml"));
|
||||
const sinon = __importStar(require("sinon"));
|
||||
const analyze_1 = require("./analyze");
|
||||
const codeql_1 = require("./codeql");
|
||||
const feature_flags_1 = require("./feature-flags");
|
||||
const languages_1 = require("./languages");
|
||||
const logging_1 = require("./logging");
|
||||
const testing_utils_1 = require("./testing-utils");
|
||||
|
|
@ -188,6 +190,126 @@ const util = __importStar(require("./util"));
|
|||
}
|
||||
}
|
||||
});
|
||||
function mockCodeQL() {
|
||||
return {
|
||||
getVersion: async () => "2.12.2",
|
||||
databaseRunQueries: sinon.spy(),
|
||||
databaseInterpretResults: async () => "",
|
||||
databasePrintBaseline: async () => "",
|
||||
};
|
||||
}
|
||||
function createBaseConfig(tmpDir) {
|
||||
return {
|
||||
languages: [],
|
||||
queries: {},
|
||||
pathsIgnore: [],
|
||||
paths: [],
|
||||
originalUserInput: {},
|
||||
tempDir: "tempDir",
|
||||
codeQLCmd: "",
|
||||
gitHubVersion: {
|
||||
type: util.GitHubVariant.DOTCOM,
|
||||
},
|
||||
dbLocation: path.resolve(tmpDir, "codeql_databases"),
|
||||
packs: {},
|
||||
debugMode: false,
|
||||
debugArtifactName: util.DEFAULT_DEBUG_ARTIFACT_NAME,
|
||||
debugDatabaseName: util.DEFAULT_DEBUG_DATABASE_NAME,
|
||||
augmentationProperties: {
|
||||
injectedMlQueries: false,
|
||||
packsInputCombines: false,
|
||||
queriesInputCombines: false,
|
||||
},
|
||||
trapCaches: {},
|
||||
trapCacheDownloadTime: 0,
|
||||
};
|
||||
}
|
||||
function createQueryConfig(builtin, custom) {
|
||||
return {
|
||||
builtin,
|
||||
custom: custom.map((c) => ({ searchPath: "/search", queries: [c] })),
|
||||
};
|
||||
}
|
||||
async function runQueriesWithConfig(config, features) {
|
||||
for (const language of config.languages) {
|
||||
fs.mkdirSync(util.getCodeQLDatabasePath(config, language), {
|
||||
recursive: true,
|
||||
});
|
||||
}
|
||||
return (0, analyze_1.runQueries)("sarif-folder", "--memFlag", "--addSnippetsFlag", "--threadsFlag", undefined, config, (0, logging_1.getRunnerLogger)(true), (0, testing_utils_1.createFeatures)(features));
|
||||
}
|
||||
function getDatabaseRunQueriesCalls(mock) {
|
||||
return mock.databaseRunQueries.getCalls();
|
||||
}
|
||||
(0, ava_1.default)("optimizeForLastQueryRun for one language", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
(0, codeql_1.setCodeQL)(codeql);
|
||||
const config = createBaseConfig(tmpDir);
|
||||
config.languages = [languages_1.Language.cpp];
|
||||
config.queries.cpp = createQueryConfig(["foo.ql"], []);
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [true]);
|
||||
});
|
||||
});
|
||||
(0, ava_1.default)("optimizeForLastQueryRun for two languages", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
(0, codeql_1.setCodeQL)(codeql);
|
||||
const config = createBaseConfig(tmpDir);
|
||||
config.languages = [languages_1.Language.cpp, languages_1.Language.java];
|
||||
config.queries.cpp = createQueryConfig(["foo.ql"], []);
|
||||
config.queries.java = createQueryConfig(["bar.ql"], []);
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [true, true]);
|
||||
});
|
||||
});
|
||||
(0, ava_1.default)("optimizeForLastQueryRun for two languages, with custom queries", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
(0, codeql_1.setCodeQL)(codeql);
|
||||
const config = createBaseConfig(tmpDir);
|
||||
config.languages = [languages_1.Language.cpp, languages_1.Language.java];
|
||||
config.queries.cpp = createQueryConfig(["foo.ql"], ["c1.ql", "c2.ql"]);
|
||||
config.queries.java = createQueryConfig(["bar.ql"], ["c3.ql"]);
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [false, false, true, false, true]);
|
||||
});
|
||||
});
|
||||
(0, ava_1.default)("optimizeForLastQueryRun for two languages, with custom queries and packs", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
(0, codeql_1.setCodeQL)(codeql);
|
||||
const config = createBaseConfig(tmpDir);
|
||||
config.languages = [languages_1.Language.cpp, languages_1.Language.java];
|
||||
config.queries.cpp = createQueryConfig(["foo.ql"], ["c1.ql", "c2.ql"]);
|
||||
config.queries.java = createQueryConfig(["bar.ql"], ["c3.ql"]);
|
||||
config.packs.cpp = ["a/cpp-pack1@0.1.0"];
|
||||
config.packs.java = ["b/java-pack1@0.2.0", "b/java-pack2@0.3.3"];
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [false, false, false, true, false, false, true]);
|
||||
});
|
||||
});
|
||||
(0, ava_1.default)("optimizeForLastQueryRun for one language, CliConfigFileEnabled", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
(0, codeql_1.setCodeQL)(codeql);
|
||||
const config = createBaseConfig(tmpDir);
|
||||
config.languages = [languages_1.Language.cpp];
|
||||
await runQueriesWithConfig(config, [feature_flags_1.Feature.CliConfigFileEnabled]);
|
||||
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [true]);
|
||||
});
|
||||
});
|
||||
(0, ava_1.default)("optimizeForLastQueryRun for two languages, CliConfigFileEnabled", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
(0, codeql_1.setCodeQL)(codeql);
|
||||
const config = createBaseConfig(tmpDir);
|
||||
config.languages = [languages_1.Language.cpp, languages_1.Language.java];
|
||||
await runQueriesWithConfig(config, [feature_flags_1.Feature.CliConfigFileEnabled]);
|
||||
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [true, true]);
|
||||
});
|
||||
});
|
||||
(0, ava_1.default)("validateQueryFilters", (t) => {
|
||||
t.notThrows(() => (0, analyze_1.validateQueryFilters)([]));
|
||||
t.notThrows(() => (0, analyze_1.validateQueryFilters)(undefined));
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
9
lib/codeql.js
generated
9
lib/codeql.js
generated
|
|
@ -472,17 +472,20 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
|||
throw new Error(`Unexpected output from codeql resolve queries: ${e}`);
|
||||
}
|
||||
},
|
||||
async databaseRunQueries(databasePath, extraSearchPath, querySuitePath, memoryFlag, threadsFlag) {
|
||||
async databaseRunQueries(databasePath, extraSearchPath, querySuitePath, flags, optimizeForLastQueryRun) {
|
||||
const codeqlArgs = [
|
||||
"database",
|
||||
"run-queries",
|
||||
memoryFlag,
|
||||
threadsFlag,
|
||||
...flags,
|
||||
databasePath,
|
||||
"--min-disk-free=1024",
|
||||
"-v",
|
||||
...getExtraOptionsFromEnv(["database", "run-queries"]),
|
||||
];
|
||||
if (optimizeForLastQueryRun &&
|
||||
(await util.supportExpectDiscardedCache(this))) {
|
||||
codeqlArgs.push("--expect-discarded-cache");
|
||||
}
|
||||
if (extraSearchPath !== undefined) {
|
||||
codeqlArgs.push("--additional-packs", extraSearchPath);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
9
lib/util.js
generated
9
lib/util.js
generated
|
|
@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseMatrixInput = exports.isHostedRunner = exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.listFolder = exports.doesDirectoryExist = exports.logCodeScanningConfigInCli = exports.useCodeScanningConfigInCli = exports.isInTestMode = exports.getMlPoweredJsQueriesStatus = exports.getMlPoweredJsQueriesPack = exports.ML_POWERED_JS_QUERIES_PACK_NAME = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.enrichEnvironment = exports.initializeEnvironment = exports.EnvVar = exports.assertNever = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DID_AUTOBUILD_GO_ENV_VAR_NAME = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
|
||||
exports.parseMatrixInput = exports.isHostedRunner = exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.listFolder = exports.doesDirectoryExist = exports.logCodeScanningConfigInCli = exports.useCodeScanningConfigInCli = exports.isInTestMode = exports.getMlPoweredJsQueriesStatus = exports.getMlPoweredJsQueriesPack = exports.ML_POWERED_JS_QUERIES_PACK_NAME = exports.supportExpectDiscardedCache = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.enrichEnvironment = exports.initializeEnvironment = exports.EnvVar = exports.assertNever = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DID_AUTOBUILD_GO_ENV_VAR_NAME = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
|
||||
const fs = __importStar(require("fs"));
|
||||
const os = __importStar(require("os"));
|
||||
const path = __importStar(require("path"));
|
||||
|
|
@ -475,6 +475,13 @@ function isGoodVersion(versionSpec) {
|
|||
return !BROKEN_VERSIONS.includes(versionSpec);
|
||||
}
|
||||
exports.isGoodVersion = isGoodVersion;
|
||||
/**
|
||||
* Checks whether the CodeQL CLI supports the `--expect-discarded-cache` command-line flag.
|
||||
*/
|
||||
async function supportExpectDiscardedCache(codeQL) {
|
||||
return codeQlVersionAbove(codeQL, "2.12.1");
|
||||
}
|
||||
exports.supportExpectDiscardedCache = supportExpectDiscardedCache;
|
||||
exports.ML_POWERED_JS_QUERIES_PACK_NAME = "codeql/javascript-experimental-atm-queries";
|
||||
/**
|
||||
* Gets the ML-powered JS query pack to add to the analysis if a repo is opted into the ML-powered
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -3,15 +3,18 @@ import * as path from "path";
|
|||
|
||||
import test, { ExecutionContext } from "ava";
|
||||
import * as yaml from "js-yaml";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import {
|
||||
convertPackToQuerySuiteEntry,
|
||||
createQuerySuiteContents,
|
||||
runQueries,
|
||||
validateQueryFilters,
|
||||
QueriesStatusReport,
|
||||
} from "./analyze";
|
||||
import { setCodeQL } from "./codeql";
|
||||
import { Config } from "./config-utils";
|
||||
import { CodeQL, setCodeQL } from "./codeql";
|
||||
import { Config, QueriesWithSearchPath } from "./config-utils";
|
||||
import { Feature } from "./feature-flags";
|
||||
import { Language } from "./languages";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { setupTests, setupActionsVars, createFeatures } from "./testing-utils";
|
||||
|
|
@ -229,6 +232,175 @@ test("status report fields and search path setting", async (t) => {
|
|||
}
|
||||
});
|
||||
|
||||
function mockCodeQL(): Partial<CodeQL> {
|
||||
return {
|
||||
getVersion: async () => "2.12.2",
|
||||
databaseRunQueries: sinon.spy(),
|
||||
databaseInterpretResults: async () => "",
|
||||
databasePrintBaseline: async () => "",
|
||||
};
|
||||
}
|
||||
|
||||
function createBaseConfig(tmpDir: string): Config {
|
||||
return {
|
||||
languages: [],
|
||||
queries: {},
|
||||
pathsIgnore: [],
|
||||
paths: [],
|
||||
originalUserInput: {},
|
||||
tempDir: "tempDir",
|
||||
codeQLCmd: "",
|
||||
gitHubVersion: {
|
||||
type: util.GitHubVariant.DOTCOM,
|
||||
} as util.GitHubVersion,
|
||||
dbLocation: path.resolve(tmpDir, "codeql_databases"),
|
||||
packs: {},
|
||||
debugMode: false,
|
||||
debugArtifactName: util.DEFAULT_DEBUG_ARTIFACT_NAME,
|
||||
debugDatabaseName: util.DEFAULT_DEBUG_DATABASE_NAME,
|
||||
augmentationProperties: {
|
||||
injectedMlQueries: false,
|
||||
packsInputCombines: false,
|
||||
queriesInputCombines: false,
|
||||
},
|
||||
trapCaches: {},
|
||||
trapCacheDownloadTime: 0,
|
||||
};
|
||||
}
|
||||
|
||||
function createQueryConfig(
|
||||
builtin: string[],
|
||||
custom: string[]
|
||||
): { builtin: string[]; custom: QueriesWithSearchPath[] } {
|
||||
return {
|
||||
builtin,
|
||||
custom: custom.map((c) => ({ searchPath: "/search", queries: [c] })),
|
||||
};
|
||||
}
|
||||
|
||||
async function runQueriesWithConfig(
|
||||
config: Config,
|
||||
features: Feature[]
|
||||
): Promise<QueriesStatusReport> {
|
||||
for (const language of config.languages) {
|
||||
fs.mkdirSync(util.getCodeQLDatabasePath(config, language), {
|
||||
recursive: true,
|
||||
});
|
||||
}
|
||||
return runQueries(
|
||||
"sarif-folder",
|
||||
"--memFlag",
|
||||
"--addSnippetsFlag",
|
||||
"--threadsFlag",
|
||||
undefined,
|
||||
config,
|
||||
getRunnerLogger(true),
|
||||
createFeatures(features)
|
||||
);
|
||||
}
|
||||
|
||||
function getDatabaseRunQueriesCalls(mock: Partial<CodeQL>) {
|
||||
return (mock.databaseRunQueries as sinon.SinonSpy).getCalls();
|
||||
}
|
||||
|
||||
test("optimizeForLastQueryRun for one language", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
setCodeQL(codeql);
|
||||
const config: Config = createBaseConfig(tmpDir);
|
||||
config.languages = [Language.cpp];
|
||||
config.queries.cpp = createQueryConfig(["foo.ql"], []);
|
||||
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[true]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("optimizeForLastQueryRun for two languages", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
setCodeQL(codeql);
|
||||
const config: Config = createBaseConfig(tmpDir);
|
||||
config.languages = [Language.cpp, Language.java];
|
||||
config.queries.cpp = createQueryConfig(["foo.ql"], []);
|
||||
config.queries.java = createQueryConfig(["bar.ql"], []);
|
||||
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[true, true]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("optimizeForLastQueryRun for two languages, with custom queries", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
setCodeQL(codeql);
|
||||
const config: Config = createBaseConfig(tmpDir);
|
||||
config.languages = [Language.cpp, Language.java];
|
||||
config.queries.cpp = createQueryConfig(["foo.ql"], ["c1.ql", "c2.ql"]);
|
||||
config.queries.java = createQueryConfig(["bar.ql"], ["c3.ql"]);
|
||||
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[false, false, true, false, true]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("optimizeForLastQueryRun for two languages, with custom queries and packs", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
setCodeQL(codeql);
|
||||
const config: Config = createBaseConfig(tmpDir);
|
||||
config.languages = [Language.cpp, Language.java];
|
||||
config.queries.cpp = createQueryConfig(["foo.ql"], ["c1.ql", "c2.ql"]);
|
||||
config.queries.java = createQueryConfig(["bar.ql"], ["c3.ql"]);
|
||||
config.packs.cpp = ["a/cpp-pack1@0.1.0"];
|
||||
config.packs.java = ["b/java-pack1@0.2.0", "b/java-pack2@0.3.3"];
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[false, false, false, true, false, false, true]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("optimizeForLastQueryRun for one language, CliConfigFileEnabled", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
setCodeQL(codeql);
|
||||
const config: Config = createBaseConfig(tmpDir);
|
||||
config.languages = [Language.cpp];
|
||||
|
||||
await runQueriesWithConfig(config, [Feature.CliConfigFileEnabled]);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[true]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("optimizeForLastQueryRun for two languages, CliConfigFileEnabled", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
const codeql = mockCodeQL();
|
||||
setCodeQL(codeql);
|
||||
const config: Config = createBaseConfig(tmpDir);
|
||||
config.languages = [Language.cpp, Language.java];
|
||||
|
||||
await runQueriesWithConfig(config, [Feature.CliConfigFileEnabled]);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[true, true]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("validateQueryFilters", (t) => {
|
||||
t.notThrows(() => validateQueryFilters([]));
|
||||
t.notThrows(() => validateQueryFilters(undefined));
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ export async function runQueries(
|
|||
const statusReport: QueriesStatusReport = {};
|
||||
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
const queryFlags = [memoryFlag, threadsFlag];
|
||||
|
||||
await util.logCodeScanningConfigInCli(codeql, featureEnablement, logger);
|
||||
|
||||
|
|
@ -231,7 +232,7 @@ export async function runQueries(
|
|||
// another to interpret the results.
|
||||
logger.startGroup(`Running queries for ${language}`);
|
||||
const startTimeBuiltIn = new Date().getTime();
|
||||
await runQueryGroup(language, "all", undefined, undefined);
|
||||
await runQueryGroup(language, "all", undefined, undefined, true);
|
||||
// TODO should not be using `builtin` here. We should be using `all` instead.
|
||||
// The status report does not support `all` yet.
|
||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||
|
|
@ -267,16 +268,24 @@ export async function runQueries(
|
|||
);
|
||||
}
|
||||
|
||||
const customQueryIndices: number[] = [];
|
||||
for (let i = 0; i < queries.custom.length; ++i) {
|
||||
if (queries.custom[i].queries.length > 0) {
|
||||
customQueryIndices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
logger.startGroup(`Running queries for ${language}`);
|
||||
const querySuitePaths: string[] = [];
|
||||
if (queries["builtin"].length > 0) {
|
||||
if (queries.builtin.length > 0) {
|
||||
const startTimeBuiltIn = new Date().getTime();
|
||||
querySuitePaths.push(
|
||||
(await runQueryGroup(
|
||||
language,
|
||||
"builtin",
|
||||
createQuerySuiteContents(queries["builtin"], queryFilters),
|
||||
undefined
|
||||
createQuerySuiteContents(queries.builtin, queryFilters),
|
||||
undefined,
|
||||
customQueryIndices.length === 0 && packsWithVersion.length === 0
|
||||
)) as string
|
||||
);
|
||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||
|
|
@ -284,21 +293,18 @@ export async function runQueries(
|
|||
}
|
||||
const startTimeCustom = new Date().getTime();
|
||||
let ranCustom = false;
|
||||
for (let i = 0; i < queries["custom"].length; ++i) {
|
||||
if (queries["custom"][i].queries.length > 0) {
|
||||
querySuitePaths.push(
|
||||
(await runQueryGroup(
|
||||
language,
|
||||
`custom-${i}`,
|
||||
createQuerySuiteContents(
|
||||
queries["custom"][i].queries,
|
||||
queryFilters
|
||||
),
|
||||
queries["custom"][i].searchPath
|
||||
)) as string
|
||||
);
|
||||
ranCustom = true;
|
||||
}
|
||||
for (const i of customQueryIndices) {
|
||||
querySuitePaths.push(
|
||||
(await runQueryGroup(
|
||||
language,
|
||||
`custom-${i}`,
|
||||
createQuerySuiteContents(queries.custom[i].queries, queryFilters),
|
||||
queries.custom[i].searchPath,
|
||||
i === customQueryIndices[customQueryIndices.length - 1] &&
|
||||
packsWithVersion.length === 0
|
||||
)) as string
|
||||
);
|
||||
ranCustom = true;
|
||||
}
|
||||
if (packsWithVersion.length > 0) {
|
||||
querySuitePaths.push(
|
||||
|
|
@ -306,7 +312,8 @@ export async function runQueries(
|
|||
language,
|
||||
"packs",
|
||||
packsWithVersion,
|
||||
queryFilters
|
||||
queryFilters,
|
||||
true
|
||||
)
|
||||
);
|
||||
ranCustom = true;
|
||||
|
|
@ -373,7 +380,8 @@ export async function runQueries(
|
|||
language: Language,
|
||||
type: string,
|
||||
querySuiteContents: string | undefined,
|
||||
searchPath: string | undefined
|
||||
searchPath: string | undefined,
|
||||
optimizeForLastQueryRun: boolean
|
||||
): Promise<string | undefined> {
|
||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
// Pass the queries to codeql using a file instead of using the command
|
||||
|
|
@ -391,8 +399,8 @@ export async function runQueries(
|
|||
databasePath,
|
||||
searchPath,
|
||||
querySuitePath,
|
||||
memoryFlag,
|
||||
threadsFlag
|
||||
queryFlags,
|
||||
optimizeForLastQueryRun
|
||||
);
|
||||
|
||||
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
||||
|
|
@ -402,7 +410,8 @@ export async function runQueries(
|
|||
language: Language,
|
||||
type: string,
|
||||
packs: string[],
|
||||
queryFilters: configUtils.QueryFilter[]
|
||||
queryFilters: configUtils.QueryFilter[],
|
||||
optimizeForLastQueryRun: boolean
|
||||
): Promise<string> {
|
||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
|
||||
|
|
@ -424,8 +433,8 @@ export async function runQueries(
|
|||
databasePath,
|
||||
undefined,
|
||||
querySuitePath,
|
||||
memoryFlag,
|
||||
threadsFlag
|
||||
queryFlags,
|
||||
optimizeForLastQueryRun
|
||||
);
|
||||
|
||||
return querySuitePath;
|
||||
|
|
|
|||
|
|
@ -148,13 +148,19 @@ export interface CodeQL {
|
|||
): Promise<void>;
|
||||
/**
|
||||
* Run 'codeql database run-queries'.
|
||||
*
|
||||
* @param optimizeForLastQueryRun Whether to apply additional optimization for
|
||||
* the last database query run in the action.
|
||||
* It is always safe to set it to false.
|
||||
* It should be set to true only for the very
|
||||
* last databaseRunQueries() call.
|
||||
*/
|
||||
databaseRunQueries(
|
||||
databasePath: string,
|
||||
extraSearchPath: string | undefined,
|
||||
querySuitePath: string | undefined,
|
||||
memoryFlag: string,
|
||||
threadsFlag: string
|
||||
flags: string[],
|
||||
optimizeForLastQueryRun: boolean
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Run 'codeql database interpret-results'.
|
||||
|
|
@ -789,19 +795,24 @@ export async function getCodeQLForCmd(
|
|||
databasePath: string,
|
||||
extraSearchPath: string | undefined,
|
||||
querySuitePath: string | undefined,
|
||||
memoryFlag: string,
|
||||
threadsFlag: string
|
||||
flags: string[],
|
||||
optimizeForLastQueryRun: boolean
|
||||
): Promise<void> {
|
||||
const codeqlArgs = [
|
||||
"database",
|
||||
"run-queries",
|
||||
memoryFlag,
|
||||
threadsFlag,
|
||||
...flags,
|
||||
databasePath,
|
||||
"--min-disk-free=1024", // Try to leave at least 1GB free
|
||||
"-v",
|
||||
...getExtraOptionsFromEnv(["database", "run-queries"]),
|
||||
];
|
||||
if (
|
||||
optimizeForLastQueryRun &&
|
||||
(await util.supportExpectDiscardedCache(this))
|
||||
) {
|
||||
codeqlArgs.push("--expect-discarded-cache");
|
||||
}
|
||||
if (extraSearchPath !== undefined) {
|
||||
codeqlArgs.push("--additional-packs", extraSearchPath);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -571,6 +571,15 @@ export function isGoodVersion(versionSpec: string) {
|
|||
return !BROKEN_VERSIONS.includes(versionSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the CodeQL CLI supports the `--expect-discarded-cache` command-line flag.
|
||||
*/
|
||||
export async function supportExpectDiscardedCache(
|
||||
codeQL: CodeQL
|
||||
): Promise<boolean> {
|
||||
return codeQlVersionAbove(codeQL, "2.12.1");
|
||||
}
|
||||
|
||||
export const ML_POWERED_JS_QUERIES_PACK_NAME =
|
||||
"codeql/javascript-experimental-atm-queries";
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue