Merge branch 'aeisenberg/unrevert-query-filters' into aeisenberg/fix-config-files

This commit is contained in:
Andrew Eisenberg
2022-08-11 14:16:50 -07:00
61 changed files with 882 additions and 112 deletions

View File

@@ -24,6 +24,7 @@ test("analyze action with RAM & threads from environment variables", async (t) =
await util.withTmpDir(async (tmpDir) => {
process.env["GITHUB_SERVER_URL"] = util.GITHUB_DOTCOM_URL;
process.env["GITHUB_REPOSITORY"] = "github/codeql-action-fake-repository";
process.env["GITHUB_API_URL"] = "https://api.github.com";
sinon
.stub(actionsUtil, "createStatusReportBase")
.resolves({} as actionsUtil.StatusReportBase);

View File

@@ -24,6 +24,7 @@ test("analyze action with RAM & threads from action inputs", async (t) => {
await util.withTmpDir(async (tmpDir) => {
process.env["GITHUB_SERVER_URL"] = util.GITHUB_DOTCOM_URL;
process.env["GITHUB_REPOSITORY"] = "github/codeql-action-fake-repository";
process.env["GITHUB_API_URL"] = "https://api.github.com";
sinon
.stub(actionsUtil, "createStatusReportBase")
.resolves({} as actionsUtil.StatusReportBase);

View File

@@ -96,6 +96,7 @@ async function run() {
const apiDetails = {
auth: actionsUtil.getRequiredInput("token"),
url: util.getRequiredEnvParam("GITHUB_SERVER_URL"),
apiURL: util.getRequiredEnvParam("GITHUB_API_URL"),
};
const outputDir = actionsUtil.getRequiredInput("output");
const threads = util.getThreadsFlag(

View File

@@ -1,11 +1,17 @@
import * as fs from "fs";
import * as path from "path";
import test from "ava";
import test, { ExecutionContext } from "ava";
import * as yaml from "js-yaml";
import * as sinon from "sinon";
import { runQueries, createdDBForScannedLanguages } from "./analyze";
import {
convertPackToQuerySuiteEntry,
createdDBForScannedLanguages,
createQuerySuiteContents,
runQueries,
validateQueryFilters,
} from "./analyze";
import { setCodeQL, getCodeQLForTesting } from "./codeql";
import { stubToolRunnerConstructor } from "./codeql.test";
import { Config } from "./config-utils";
@@ -256,6 +262,164 @@ test("status report fields and search path setting", async (t) => {
}
});
test("validateQueryFilters", (t) => {
t.notThrows(() => validateQueryFilters([]));
t.notThrows(() => validateQueryFilters(undefined));
t.notThrows(() => {
return validateQueryFilters([
{
exclude: {
"problem.severity": "recommendation",
},
},
{
exclude: {
"tags contain": ["foo", "bar"],
},
},
{
include: {
"problem.severity": "something-to-think-about",
},
},
{
include: {
"tags contain": ["baz", "bop"],
},
},
]);
});
t.throws(
() => {
return validateQueryFilters([
{
exclude: {
"tags contain": ["foo", "bar"],
},
include: {
"tags contain": ["baz", "bop"],
},
},
]);
},
{ message: /Query filter must have exactly one key/ }
);
t.throws(
() => {
return validateQueryFilters([{ xxx: "foo" } as any]);
},
{ message: /Only "include" or "exclude" filters are allowed/ }
);
});
const convertPackToQuerySuiteEntryMacro = test.macro({
exec: (t: ExecutionContext<unknown>, packSpec: string, suiteEntry: any) =>
t.deepEqual(convertPackToQuerySuiteEntry(packSpec), suiteEntry),
title: (_providedTitle, packSpec: string) => `Query Suite Entry: ${packSpec}`,
});
test(convertPackToQuerySuiteEntryMacro, "a/b", {
qlpack: "a/b",
from: undefined,
version: undefined,
query: undefined,
queries: undefined,
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3", {
qlpack: "a/b",
from: undefined,
version: "~1.2.3",
query: undefined,
queries: undefined,
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b:my/path", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: undefined,
queries: "my/path",
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: undefined,
queries: "my/path",
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b:my/path/query.ql", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: "my/path/query.ql",
queries: undefined,
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path/query.ql", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: "my/path/query.ql",
queries: undefined,
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b:my/path/suite.qls", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: undefined,
queries: undefined,
apply: "my/path/suite.qls",
});
test(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path/suite.qls", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: undefined,
queries: undefined,
apply: "my/path/suite.qls",
});
test("convertPackToQuerySuiteEntry Failure", (t) => {
t.throws(() => convertPackToQuerySuiteEntry("this-is-not-a-pack"));
});
test("createQuerySuiteContents", (t) => {
const yamlResult = createQuerySuiteContents(
["query1.ql", "query2.ql"],
[
{
exclude: { "problem.severity": "recommendation" },
},
{
include: { "problem.severity": "recommendation" },
},
]
);
const expected = `- query: query1.ql
- query: query2.ql
- exclude:
problem.severity: recommendation
- include:
problem.severity: recommendation
`;
t.deepEqual(yamlResult, expected);
});
const stubConfig: Config = {
languages: [Language.cpp, Language.go],
queries: {},

View File

@@ -224,6 +224,9 @@ export async function runQueries(
const codeql = await getCodeQL(config.codeQLCmd);
for (const language of config.languages) {
const queries = config.queries[language];
const queryFilters = validateQueryFilters(
config.originalUserInput["query-filters"]
);
const packsWithVersion = config.packs[language] || [];
const hasBuiltinQueries = queries?.builtin.length > 0;
@@ -288,7 +291,7 @@ export async function runQueries(
(await runQueryGroup(
language,
"builtin",
createQuerySuiteContents(queries["builtin"]),
createQuerySuiteContents(queries["builtin"], queryFilters),
undefined
)) as string
);
@@ -303,7 +306,10 @@ export async function runQueries(
(await runQueryGroup(
language,
`custom-${i}`,
createQuerySuiteContents(queries["custom"][i].queries),
createQuerySuiteContents(
queries["custom"][i].queries,
queryFilters
),
queries["custom"][i].searchPath
)) as string
);
@@ -312,12 +318,12 @@ export async function runQueries(
}
if (packsWithVersion.length > 0) {
querySuitePaths.push(
...(await runQueryPacks(
await runQueryPacks(
language,
"packs",
packsWithVersion,
undefined
))
queryFilters
)
);
ranCustom = true;
}
@@ -427,31 +433,60 @@ export async function runQueries(
language: Language,
type: string,
packs: string[],
searchPath: string | undefined
): Promise<string[]> {
queryFilters: configUtils.QueryFilter[]
): Promise<string> {
const databasePath = util.getCodeQLDatabasePath(config, language);
// Run the queries individually instead of all at once to avoid command
// line length restrictions, particularly on windows.
for (const pack of packs) {
logger.debug(`Running query pack for ${language}-${type}: ${pack}`);
await codeql.databaseRunQueries(
databasePath,
searchPath,
pack,
memoryFlag,
threadsFlag
);
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
}
return packs;
// combine the list of packs into a query suite in order to run them all simultaneously.
const querySuite = (
packs.map(convertPackToQuerySuiteEntry) as configUtils.QuerySuiteEntry[]
).concat(queryFilters);
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
);
return querySuitePath;
}
}
function createQuerySuiteContents(queries: string[]) {
return queries.map((q: string) => `- query: ${q}`).join("\n");
export function convertPackToQuerySuiteEntry(
packStr: string
): configUtils.QuerySuitePackEntry {
const pack = configUtils.parsePacksSpecification(packStr);
return {
qlpack: !pack.path ? pack.name : undefined,
from: pack.path ? pack.name : undefined,
version: pack.version,
query: pack.path?.endsWith(".ql") ? pack.path : undefined,
queries:
!pack.path?.endsWith(".ql") && !pack.path?.endsWith(".qls")
? pack.path
: undefined,
apply: pack.path?.endsWith(".qls") ? pack.path : undefined,
};
}
export function createQuerySuiteContents(
queries: string[],
queryFilters: configUtils.QueryFilter[]
) {
return yaml.dump(
queries.map((q: string) => ({ query: q })).concat(queryFilters as any)
);
}
export async function runFinalize(
@@ -551,3 +586,33 @@ function printLinesOfCodeSummary(
);
}
}
// exported for testing
export function validateQueryFilters(queryFilters?: configUtils.QueryFilter[]) {
if (!queryFilters) {
return [];
}
const errors: string[] = [];
for (const qf of queryFilters) {
const keys = Object.keys(qf);
if (keys.length !== 1) {
errors.push(
`Query filter must have exactly one key: ${JSON.stringify(qf)}`
);
}
if (!["exclude", "include"].includes(keys[0])) {
errors.push(
`Only "include" or "exclude" filters are allowed:\n${JSON.stringify(
qf
)}`
);
}
}
if (errors.length) {
throw new Error(`Invalid query filter.\n${errors.join("\n")}`);
}
return queryFilters;
}

View File

@@ -87,6 +87,23 @@ test("Get the client API with github url", async (t) => {
);
});
test("Get the API with an API URL directly", async (t) => {
doTest(
t,
{
auth: "xyz",
url: "http://github.localhost",
apiURL: "http://api.github.localhost",
},
undefined,
{
auth: "token xyz",
baseUrl: "http://api.github.localhost",
userAgent: `CodeQL-Action/${pkg.version}`,
}
);
});
function doTest(
t: ExecutionContext<unknown>,
clientArgs: any,

View File

@@ -22,11 +22,13 @@ export type GitHubApiCombinedDetails = GitHubApiDetails &
export interface GitHubApiDetails {
auth: string;
url: string;
apiURL: string | undefined;
}
export interface GitHubApiExternalRepoDetails {
externalRepoAuth?: string;
url: string;
apiURL: string | undefined;
}
export const getApiClient = function (
@@ -36,16 +38,18 @@ export const getApiClient = function (
const auth =
(allowExternal && apiDetails.externalRepoAuth) || apiDetails.auth;
const retryingOctokit = githubUtils.GitHub.plugin(retry.retry);
const apiURL = apiDetails.apiURL || deriveApiUrl(apiDetails.url);
return new retryingOctokit(
githubUtils.getOctokitOptions(auth, {
baseUrl: getApiUrl(apiDetails.url),
baseUrl: apiURL,
userAgent: `CodeQL-${getMode()}/${pkg.version}`,
log: consoleLogLevel({ level: "debug" }),
})
);
};
function getApiUrl(githubUrl: string): string {
// Once the runner is deleted, this can also be removed since the GitHub API URL is always available in an environment variable on Actions.
function deriveApiUrl(githubUrl: string): string {
const url = new URL(githubUrl);
// If we detect this is trying to connect to github.com
@@ -63,6 +67,7 @@ function getApiDetails() {
return {
auth: getRequiredInput("token"),
url: getRequiredEnvParam("GITHUB_SERVER_URL"),
apiURL: getRequiredEnvParam("GITHUB_API_URL"),
};
}

View File

@@ -24,11 +24,13 @@ setupTests(test);
const sampleApiDetails = {
auth: "token",
url: "https://github.com",
apiURL: undefined,
};
const sampleGHAEApiDetails = {
auth: "token",
url: "https://example.githubenterprise.com",
apiURL: undefined,
};
let stubConfig: Config;

View File

@@ -20,6 +20,7 @@ const sampleApiDetails = {
auth: "token",
externalRepoAuth: "token",
url: "https://github.example.com",
apiURL: undefined,
};
const gitHubVersion = { type: util.GitHubVariant.DOTCOM } as util.GitHubVersion;
@@ -1609,6 +1610,60 @@ test(invalidPackNameMacro, "c/d@../a");
test(invalidPackNameMacro, "c/d@b/../a");
test(invalidPackNameMacro, "c/d:z@1");
/**
* Test macro for pretty printing pack specs
*/
const packSpecPrettyPrintingMacro = test.macro({
exec: (t: ExecutionContext, packStr: string, packObj: configUtils.Pack) => {
const parsed = configUtils.parsePacksSpecification(packStr);
t.deepEqual(parsed, packObj, "parsed pack spec is correct");
const stringified = configUtils.prettyPrintPack(packObj);
t.deepEqual(
stringified,
packStr.trim(),
"pretty-printed pack spec is correct"
);
t.deepEqual(
configUtils.validatePackSpecification(packStr),
packStr.trim(),
"pack spec is valid"
);
},
title: (
_providedTitle: string | undefined,
packStr: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_packObj: configUtils.Pack
) => `Prettyprint pack spec: '${packStr}'`,
});
test(packSpecPrettyPrintingMacro, "a/b", {
name: "a/b",
version: undefined,
path: undefined,
});
test(packSpecPrettyPrintingMacro, "a/b@~1.2.3", {
name: "a/b",
version: "~1.2.3",
path: undefined,
});
test(packSpecPrettyPrintingMacro, "a/b@~1.2.3:abc/def", {
name: "a/b",
version: "~1.2.3",
path: "abc/def",
});
test(packSpecPrettyPrintingMacro, "a/b:abc/def", {
name: "a/b",
version: undefined,
path: "abc/def",
});
test(packSpecPrettyPrintingMacro, " a/b:abc/def ", {
name: "a/b",
version: undefined,
path: "abc/def",
});
/**
* Test macro for testing the packs block and the packs input
*/

View File

@@ -50,8 +50,38 @@ export interface UserConfig {
// language. If this is a single language analysis, then no split by
// language is necessary.
packs?: Record<string, string[]> | string[];
// Set of query filters to include and exclude extra queries based on
// codeql query suite `include` and `exclude` properties
"query-filters"?: QueryFilter[];
}
export type QueryFilter = ExcludeQueryFilter | IncludeQueryFilter;
interface ExcludeQueryFilter {
exclude: Record<string, string[] | string>;
}
interface IncludeQueryFilter {
include: Record<string, string[] | string>;
}
export type QuerySuitePackEntry = {
version?: string;
} & (
| {
qlpack: string;
}
| {
from?: string;
query?: string;
queries?: string;
apply?: string;
}
);
export type QuerySuiteEntry = QuerySuitePackEntry | QueryFilter;
/**
* Lists of query files for each language.
* Will only contain .ql files and not other kinds of files,
@@ -201,9 +231,14 @@ export const defaultAugmentationProperties: AugmentationProperties = {
packsInput: undefined,
queriesInput: undefined,
};
export type Packs = Partial<Record<Language, string[]>>;
export interface Pack {
name: string;
version?: string;
path?: string;
}
/**
* A list of queries from https://github.com/github/codeql that
* we don't want to run. Disabling them here is a quicker alternative to
@@ -366,11 +401,7 @@ async function addBuiltinSuiteQueries(
}
function isMlPoweredJsQueriesPack(pack: string) {
return (
pack === ML_POWERED_JS_QUERIES_PACK_NAME ||
pack.startsWith(`${ML_POWERED_JS_QUERIES_PACK_NAME}@`) ||
pack.startsWith(`${ML_POWERED_JS_QUERIES_PACK_NAME}:`)
);
return parsePacksSpecification(pack).name === ML_POWERED_JS_QUERIES_PACK_NAME;
}
/**
@@ -1311,10 +1342,10 @@ export function parsePacksFromConfig(
throw new Error(getPacksRequireLanguage(configFile, lang));
}
}
packs[lang] = [];
for (const packStr of packsArr) {
packs[lang].push(validatePacksSpecification(packStr, configFile));
}
packs[lang] = packsArr.map((packStr) =>
validatePackSpecification(packStr, configFile)
);
}
return packs;
}
@@ -1352,7 +1383,7 @@ function parsePacksFromInput(
return {
[languages[0]]: rawPacksInput.split(",").reduce((packs, pack) => {
packs.push(validatePacksSpecification(pack));
packs.push(validatePackSpecification(pack, ""));
return packs;
}, [] as string[]),
};
@@ -1376,10 +1407,10 @@ function parsePacksFromInput(
* @param packStr the package specification to verify.
* @param configFile Config file to use for error reporting
*/
export function validatePacksSpecification(
export function parsePacksSpecification(
packStr: string,
configFile?: string
): string {
): Pack {
if (typeof packStr !== "string") {
throw new Error(getPacksStrInvalid(packStr, configFile));
}
@@ -1438,9 +1469,21 @@ export function validatePacksSpecification(
throw new Error(getPacksStrInvalid(packStr, configFile));
}
return (
packName + (version ? `@${version}` : "") + (packPath ? `:${packPath}` : "")
);
return {
name: packName,
version,
path: packPath,
};
}
export function prettyPrintPack(pack: Pack) {
return `${pack.name}${pack.version ? `@${pack.version}` : ""}${
pack.path ? `:${pack.path}` : ""
}`;
}
export function validatePackSpecification(pack: string, configFile?: string) {
return prettyPrintPack(parsePacksSpecification(pack, configFile));
}
// exported for testing

View File

@@ -38,6 +38,7 @@ const testRepoName: RepositoryNwo = { owner: "github", repo: "example" };
const testApiDetails: GitHubApiDetails = {
auth: "1234",
url: "https://github.com",
apiURL: undefined,
};
function getTestConfig(tmpDir: string): Config {

View File

@@ -85,7 +85,11 @@ test("checkoutExternalQueries", async (t) => {
await externalQueries.checkoutExternalRepository(
repoName,
commit1Sha,
{ url: `file://${testRepoBaseDir}`, externalRepoAuth: "" },
{
url: `file://${testRepoBaseDir}`,
externalRepoAuth: "",
apiURL: undefined,
},
tmpDir,
getRunnerLogger(true)
);
@@ -99,7 +103,11 @@ test("checkoutExternalQueries", async (t) => {
await externalQueries.checkoutExternalRepository(
repoName,
commit2Sha,
{ url: `file://${testRepoBaseDir}`, externalRepoAuth: "" },
{
url: `file://${testRepoBaseDir}`,
externalRepoAuth: "",
apiURL: undefined,
},
tmpDir,
getRunnerLogger(true)
);
@@ -114,6 +122,7 @@ test("buildCheckoutURL", (t) => {
externalQueries.buildCheckoutURL("foo/bar", {
url: "https://github.com",
externalRepoAuth: undefined,
apiURL: undefined,
}),
"https://github.com/foo/bar"
);
@@ -121,6 +130,7 @@ test("buildCheckoutURL", (t) => {
externalQueries.buildCheckoutURL("foo/bar", {
url: "https://github.example.com/",
externalRepoAuth: undefined,
apiURL: undefined,
}),
"https://github.example.com/foo/bar"
);
@@ -129,6 +139,7 @@ test("buildCheckoutURL", (t) => {
externalQueries.buildCheckoutURL("foo/bar", {
url: "https://github.com",
externalRepoAuth: "abc",
apiURL: undefined,
}),
"https://x-access-token:abc@github.com/foo/bar"
);
@@ -136,6 +147,7 @@ test("buildCheckoutURL", (t) => {
externalQueries.buildCheckoutURL("foo/bar", {
url: "https://github.example.com/",
externalRepoAuth: "abc",
apiURL: undefined,
}),
"https://x-access-token:abc@github.example.com/foo/bar"
);

View File

@@ -23,6 +23,7 @@ test.beforeEach(() => {
const testApiDetails: GitHubApiDetails = {
auth: "1234",
url: "https://github.com",
apiURL: undefined,
};
const testRepositoryNwo = parseRepositoryNwo("github/example");

View File

@@ -134,6 +134,7 @@ async function run() {
auth: getRequiredInput("token"),
externalRepoAuth: getOptionalInput("external-repository-token"),
url: getRequiredEnvParam("GITHUB_SERVER_URL"),
apiURL: getRequiredEnvParam("GITHUB_API_URL"),
};
const gitHubVersion = await getGitHubVersionActionsOnly();

View File

@@ -202,6 +202,7 @@ program
auth,
externalRepoAuth: auth,
url: parseGitHubUrl(cmd.githubUrl),
apiURL: undefined,
};
const gitHubVersion = await getGitHubVersion(apiDetails);
@@ -475,6 +476,7 @@ program
const apiDetails = {
auth,
url: parseGitHubUrl(cmd.githubUrl),
apiURL: undefined,
};
const outputDir =
@@ -587,6 +589,7 @@ program
const apiDetails = {
auth,
url: parseGitHubUrl(cmd.githubUrl),
apiURL: undefined,
};
try {
const gitHubVersion = await getGitHubVersion(apiDetails);

View File

@@ -56,6 +56,7 @@ async function run() {
const apiDetails = {
auth: actionsUtil.getRequiredInput("token"),
url: getRequiredEnvParam("GITHUB_SERVER_URL"),
apiURL: getRequiredEnvParam("GITHUB_API_URL"),
};
const gitHubVersion = await getGitHubVersionActionsOnly();

View File

@@ -208,6 +208,7 @@ test("getGitHubVersion", async (t) => {
const v = await util.getGitHubVersion({
auth: "",
url: "https://github.com",
apiURL: undefined,
});
t.deepEqual(util.GitHubVariant.DOTCOM, v.type);
@@ -215,6 +216,7 @@ test("getGitHubVersion", async (t) => {
const v2 = await util.getGitHubVersion({
auth: "",
url: "https://ghe.example.com",
apiURL: undefined,
});
t.deepEqual(
{ type: util.GitHubVariant.GHES, version: "2.0" } as util.GitHubVersion,
@@ -225,6 +227,7 @@ test("getGitHubVersion", async (t) => {
const ghae = await util.getGitHubVersion({
auth: "",
url: "https://example.githubenterprise.com",
apiURL: undefined,
});
t.deepEqual({ type: util.GitHubVariant.GHAE }, ghae);
@@ -232,6 +235,7 @@ test("getGitHubVersion", async (t) => {
const v3 = await util.getGitHubVersion({
auth: "",
url: "https://ghe.example.com",
apiURL: undefined,
});
t.deepEqual({ type: util.GitHubVariant.DOTCOM }, v3);
});
@@ -299,13 +303,13 @@ const ML_POWERED_JS_STATUS_TESTS: Array<[string[], string]> = [
// If no packs are loaded, status is false.
[[], "false"],
// If another pack is loaded but not the ML-powered query pack, status is false.
[["someOtherPack"], "false"],
[["some-other/pack"], "false"],
// If the ML-powered query pack is loaded with a specific version, status is that version.
[[`${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`], "~0.1.0"],
// If the ML-powered query pack is loaded with a specific version and another pack is loaded, the
// status is the version of the ML-powered query pack.
[
["someOtherPack", `${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`],
["some-other/pack", `${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`],
"~0.1.0",
],
// If the ML-powered query pack is loaded without a version, the status is "latest".
@@ -320,7 +324,7 @@ const ML_POWERED_JS_STATUS_TESTS: Array<[string[], string]> = [
],
// If the ML-powered query pack is loaded with no specific version, and another pack is loaded,
// the status is "latest".
[["someOtherPack", util.ML_POWERED_JS_QUERIES_PACK_NAME], "latest"],
[["some-other/pack", util.ML_POWERED_JS_QUERIES_PACK_NAME], "latest"],
];
for (const [packs, expectedStatus] of ML_POWERED_JS_STATUS_TESTS) {

View File

@@ -15,7 +15,11 @@ import {
CODEQL_VERSION_CONFIG_FILES,
CODEQL_VERSION_NEW_TRACING,
} from "./codeql";
import { Config } from "./config-utils";
import {
Config,
parsePacksSpecification,
prettyPrintPack,
} from "./config-utils";
import { Language } from "./languages";
import { Logger } from "./logging";
@@ -679,7 +683,10 @@ export async function getMlPoweredJsQueriesPack(
} else {
version = `~0.1.0`;
}
return `${ML_POWERED_JS_QUERIES_PACK_NAME}@${version}`;
return prettyPrintPack({
name: ML_POWERED_JS_QUERIES_PACK_NAME,
version,
});
}
/**
@@ -705,11 +712,10 @@ export async function getMlPoweredJsQueriesPack(
*/
export function getMlPoweredJsQueriesStatus(config: Config): string {
const mlPoweredJsQueryPacks = (config.packs.javascript || [])
.map((pack) => pack.split("@"))
.map((p) => parsePacksSpecification(p))
.filter(
(packNameVersion) =>
packNameVersion[0] === "codeql/javascript-experimental-atm-queries" &&
packNameVersion.length <= 2
(pack) =>
pack.name === "codeql/javascript-experimental-atm-queries" && !pack.path
);
switch (mlPoweredJsQueryPacks.length) {
case 1:
@@ -718,7 +724,7 @@ export function getMlPoweredJsQueriesStatus(config: Config): string {
// with each version of the CodeQL Action. Therefore in practice we should only hit the
// `latest` case here when customers have explicitly added the ML-powered query pack to their
// CodeQL config.
return mlPoweredJsQueryPacks[0][1] || "latest";
return mlPoweredJsQueryPacks[0].version || "latest";
case 0:
return "false";
default: