Use new default version to set up CodeQL

This commit is contained in:
Henry Mercer 2023-01-10 13:16:22 +00:00
parent bd2f52fcef
commit c3be36f5cb
15 changed files with 521 additions and 314 deletions

26
lib/codeql.js generated
View file

@ -23,16 +23,14 @@ exports.getExtraOptions = exports.getCodeQLForCmd = exports.getCodeQLForTesting
const fs = __importStar(require("fs")); 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 yaml = __importStar(require("js-yaml")); const yaml = __importStar(require("js-yaml"));
const actions_util_1 = require("./actions-util"); const actions_util_1 = require("./actions-util");
const error_matcher_1 = require("./error-matcher"); const error_matcher_1 = require("./error-matcher");
const languages_1 = require("./languages"); const languages_1 = require("./languages");
const setup_codeql_1 = require("./setup-codeql"); const setupCodeql = __importStar(require("./setup-codeql"));
const toolrunner_error_catcher_1 = require("./toolrunner-error-catcher"); const toolrunner_error_catcher_1 = require("./toolrunner-error-catcher");
const trap_caching_1 = require("./trap-caching"); const trap_caching_1 = require("./trap-caching");
const util = __importStar(require("./util")); const util = __importStar(require("./util"));
const util_1 = require("./util");
class CommandInvocationError extends Error { class CommandInvocationError extends Error {
constructor(cmd, args, exitCode, error, output) { constructor(cmd, args, exitCode, error, output) {
super(`Failure invoking ${cmd} with arguments ${args}.\n super(`Failure invoking ${cmd} with arguments ${args}.\n
@ -100,29 +98,15 @@ exports.CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = "2.10.3";
* @param tempDir * @param tempDir
* @param variant * @param variant
* @param bypassToolcache * @param bypassToolcache
* @param defaultCliVersion
* @param logger * @param logger
* @param checkVersion Whether to check that CodeQL CLI meets the minimum * @param checkVersion Whether to check that CodeQL CLI meets the minimum
* version requirement. Must be set to true outside tests. * version requirement. Must be set to true outside tests.
* @returns a { CodeQL, toolsVersion } object. * @returns a { CodeQL, toolsVersion } object.
*/ */
async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolcache, logger, checkVersion) { async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger, checkVersion) {
try { try {
const source = await (0, setup_codeql_1.getCodeQLSource)(toolsInput, bypassToolcache, apiDetails, variant, logger); const { codeqlFolder, toolsVersion } = await setupCodeql.setupCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger);
let codeqlFolder;
switch (source.sourceType) {
case "local":
codeqlFolder = await toolcache.extractTar(source.codeqlTarPath);
break;
case "toolcache":
codeqlFolder = source.codeqlFolder;
logger.debug(`CodeQL found in cache ${codeqlFolder}`);
break;
case "download":
codeqlFolder = await (0, setup_codeql_1.downloadCodeQL)(source.codeqlURL, source.semanticVersion, apiDetails, tempDir, logger);
break;
default:
(0, util_1.assertNever)(source);
}
let codeqlCmd = path.join(codeqlFolder, "codeql", "codeql"); let codeqlCmd = path.join(codeqlFolder, "codeql", "codeql");
if (process.platform === "win32") { if (process.platform === "win32") {
codeqlCmd += ".exe"; codeqlCmd += ".exe";
@ -131,7 +115,7 @@ async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolc
throw new Error(`Unsupported platform: ${process.platform}`); throw new Error(`Unsupported platform: ${process.platform}`);
} }
cachedCodeQL = await getCodeQLForCmd(codeqlCmd, checkVersion); cachedCodeQL = await getCodeQLForCmd(codeqlCmd, checkVersion);
return { codeql: cachedCodeQL, toolsVersion: source.toolsVersion }; return { codeql: cachedCodeQL, toolsVersion };
} }
catch (e) { catch (e) {
logger.error(e instanceof Error ? e : new Error(String(e))); logger.error(e instanceof Error ? e : new Error(String(e)));

File diff suppressed because one or more lines are too long

115
lib/codeql.test.js generated
View file

@ -53,6 +53,10 @@ const sampleGHAEApiDetails = {
url: "https://example.githubenterprise.com", url: "https://example.githubenterprise.com",
apiURL: "https://example.githubenterprise.com/api/v3", apiURL: "https://example.githubenterprise.com/api/v3",
}; };
const SAMPLE_DEFAULT_CLI_VERSION = {
cliVersion: "2.0.0",
variant: util.GitHubVariant.DOTCOM,
};
let stubConfig; let stubConfig;
ava_1.default.beforeEach(() => { ava_1.default.beforeEach(() => {
(0, util_1.initializeEnvironment)("1.2.3"); (0, util_1.initializeEnvironment)("1.2.3");
@ -105,7 +109,7 @@ async function mockDownloadApi({ apiDetails = sampleApiDetails, isPinned, tagNam
} }
async function installIntoToolcache({ apiDetails = sampleApiDetails, isPinned, tagName, tmpDir, }) { async function installIntoToolcache({ apiDetails = sampleApiDetails, isPinned, tagName, tmpDir, }) {
const url = await mockDownloadApi({ apiDetails, isPinned, tagName }); const url = await mockDownloadApi({ apiDetails, isPinned, tagName });
await codeql.setupCodeQL(url, apiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, (0, logging_1.getRunnerLogger)(true), false); await codeql.setupCodeQL(url, apiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
} }
(0, ava_1.default)("downloads and caches explicitly requested bundles that aren't in the toolcache", async (t) => { (0, ava_1.default)("downloads and caches explicitly requested bundles that aren't in the toolcache", async (t) => {
await util.withTmpDir(async (tmpDir) => { await util.withTmpDir(async (tmpDir) => {
@ -117,9 +121,9 @@ async function installIntoToolcache({ apiDetails = sampleApiDetails, isPinned, t
tagName: `codeql-bundle-${version}`, tagName: `codeql-bundle-${version}`,
isPinned: false, isPinned: false,
}); });
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, (0, logging_1.getRunnerLogger)(true), false); const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.assert(toolcache.find("CodeQL", `0.0.0-${version}`)); t.assert(toolcache.find("CodeQL", `0.0.0-${version}`));
t.is(result.toolsVersion, version); t.is(result.toolsVersion, `0.0.0-${version}`);
} }
t.is(toolcache.findAllVersions("CodeQL").length, 2); t.is(toolcache.findAllVersions("CodeQL").length, 2);
}); });
@ -135,42 +139,52 @@ async function installIntoToolcache({ apiDetails = sampleApiDetails, isPinned, t
const url = await mockDownloadApi({ const url = await mockDownloadApi({
tagName: "codeql-bundle-20200610", tagName: "codeql-bundle-20200610",
}); });
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, (0, logging_1.getRunnerLogger)(true), false); const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.assert(toolcache.find("CodeQL", "0.0.0-20200610")); t.assert(toolcache.find("CodeQL", "0.0.0-20200610"));
t.deepEqual(result.toolsVersion, "20200610"); t.deepEqual(result.toolsVersion, "0.0.0-20200610");
}); });
}); });
(0, ava_1.default)("uses a cached bundle when no tools input is given", async (t) => { for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
await util.withTmpDir(async (tmpDir) => { (0, ava_1.default)(`uses a cached bundle when no tools input is given on ${util.GitHubVariant[variant]}`, async (t) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); await util.withTmpDir(async (tmpDir) => {
await installIntoToolcache({ (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
tagName: "codeql-bundle-20200601", await installIntoToolcache({
isPinned: true, tagName: "codeql-bundle-20200601",
tmpDir, isPinned: true,
tmpDir,
});
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, variant, false, {
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant,
}, (0, logging_1.getRunnerLogger)(true), false);
t.deepEqual(result.toolsVersion, "0.0.0-20200601");
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 1);
}); });
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, (0, logging_1.getRunnerLogger)(true), false);
t.deepEqual(result.toolsVersion, "0.0.0-20200601");
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 1);
}); });
}); (0, ava_1.default)(`downloads bundle if only an unpinned version is cached on ${util.GitHubVariant[variant]}`, async (t) => {
(0, ava_1.default)("downloads bundle if only an unpinned version is cached", async (t) => { await util.withTmpDir(async (tmpDir) => {
await util.withTmpDir(async (tmpDir) => { (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); await installIntoToolcache({
await installIntoToolcache({ tagName: "codeql-bundle-20200601",
tagName: "codeql-bundle-20200601", isPinned: false,
isPinned: false, tmpDir,
tmpDir, });
await mockDownloadApi({
tagName: defaults.bundleVersion,
});
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, variant, false, {
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant,
}, (0, logging_1.getRunnerLogger)(true), false);
t.deepEqual(result.toolsVersion, defaults.cliVersion);
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 2);
}); });
await mockDownloadApi({
tagName: defaults.bundleVersion,
});
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, (0, logging_1.getRunnerLogger)(true), false);
t.deepEqual(result.toolsVersion, defaults.bundleVersion.replace("codeql-bundle-", ""));
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 2);
}); });
}); }
(0, ava_1.default)('downloads bundle if "latest" tools specified but not cached', async (t) => { (0, ava_1.default)('downloads bundle if "latest" tools specified but not cached', async (t) => {
await util.withTmpDir(async (tmpDir) => { await util.withTmpDir(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
@ -182,39 +196,12 @@ async function installIntoToolcache({ apiDetails = sampleApiDetails, isPinned, t
await mockDownloadApi({ await mockDownloadApi({
tagName: defaults.bundleVersion, tagName: defaults.bundleVersion,
}); });
const result = await codeql.setupCodeQL("latest", sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, (0, logging_1.getRunnerLogger)(true), false); const result = await codeql.setupCodeQL("latest", sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.deepEqual(result.toolsVersion, defaults.bundleVersion.replace("codeql-bundle-", "")); t.deepEqual(result.toolsVersion, defaults.cliVersion);
const cachedVersions = toolcache.findAllVersions("CodeQL"); const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 2); t.is(cachedVersions.length, 2);
}); });
}); });
const TOOLCACHE_BYPASS_TEST_CASES = [
[true, undefined, true],
[false, undefined, false],
[
true,
"https://github.com/github/codeql-action/releases/download/codeql-bundle-20200601/codeql-bundle.tar.gz",
false,
],
];
for (const [isFeatureEnabled, toolsInput, shouldToolcacheBeBypassed,] of TOOLCACHE_BYPASS_TEST_CASES) {
(0, ava_1.default)(`download codeql bundle ${shouldToolcacheBeBypassed ? "bypasses" : "does not bypass"} toolcache when feature ${isFeatureEnabled ? "enabled" : "disabled"} and tools: ${toolsInput} passed`, async (t) => {
await util.withTmpDir(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
await installIntoToolcache({
tagName: "codeql-bundle-20200601",
isPinned: true,
tmpDir,
});
await mockDownloadApi({
tagName: defaults.bundleVersion,
});
await codeql.setupCodeQL(toolsInput, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, isFeatureEnabled, (0, logging_1.getRunnerLogger)(true), false);
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, shouldToolcacheBeBypassed ? 2 : 1);
});
});
}
(0, ava_1.default)("download codeql bundle from github ae endpoint", async (t) => { (0, ava_1.default)("download codeql bundle from github ae endpoint", async (t) => {
await util.withTmpDir(async (tmpDir) => { await util.withTmpDir(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
@ -255,7 +242,11 @@ for (const [isFeatureEnabled, toolsInput, shouldToolcacheBeBypassed,] of TOOLCAC
.returns(sampleGHAEApiDetails.apiURL); .returns(sampleGHAEApiDetails.apiURL);
sinon.stub(actionsUtil, "isRunningLocalAction").returns(false); sinon.stub(actionsUtil, "isRunningLocalAction").returns(false);
process.env["GITHUB_ACTION_REPOSITORY"] = "github/codeql-action"; process.env["GITHUB_ACTION_REPOSITORY"] = "github/codeql-action";
await codeql.setupCodeQL(undefined, sampleGHAEApiDetails, tmpDir, util.GitHubVariant.GHAE, false, (0, logging_1.getRunnerLogger)(true), false); await codeql.setupCodeQL(undefined, sampleGHAEApiDetails, tmpDir, util.GitHubVariant.GHAE, false, {
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant: util.GitHubVariant.GHAE,
}, (0, logging_1.getRunnerLogger)(true), false);
const cachedVersions = toolcache.findAllVersions("CodeQL"); const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 1); t.is(cachedVersions.length, 1);
}); });

File diff suppressed because one or more lines are too long

3
lib/init-action.js generated
View file

@ -95,7 +95,8 @@ async function run() {
if (!(await (0, actions_util_1.sendStatusReport)(await (0, actions_util_1.createStatusReportBase)("init", "starting", startedAt, workflowErrors)))) { if (!(await (0, actions_util_1.sendStatusReport)(await (0, actions_util_1.createStatusReportBase)("init", "starting", startedAt, workflowErrors)))) {
return; return;
} }
const initCodeQLResult = await (0, init_1.initCodeQL)((0, actions_util_1.getOptionalInput)("tools"), apiDetails, (0, actions_util_1.getTemporaryDirectory)(), gitHubVersion.type, await (0, util_1.shouldBypassToolcache)(features, (0, actions_util_1.getOptionalInput)("tools"), (0, actions_util_1.getOptionalInput)("languages"), repositoryNwo, logger), logger); const defaultCliVersion = await features.getDefaultCliVersion(gitHubVersion.type);
const initCodeQLResult = await (0, init_1.initCodeQL)((0, actions_util_1.getOptionalInput)("tools"), apiDetails, (0, actions_util_1.getTemporaryDirectory)(), gitHubVersion.type, await (0, util_1.shouldBypassToolcache)(features, (0, actions_util_1.getOptionalInput)("tools"), (0, actions_util_1.getOptionalInput)("languages"), repositoryNwo, logger), defaultCliVersion, logger);
codeql = initCodeQLResult.codeql; codeql = initCodeQLResult.codeql;
toolsVersion = initCodeQLResult.toolsVersion; toolsVersion = initCodeQLResult.toolsVersion;
await (0, util_1.enrichEnvironment)(codeql); await (0, util_1.enrichEnvironment)(codeql);

File diff suppressed because one or more lines are too long

4
lib/init.js generated
View file

@ -30,9 +30,9 @@ const configUtils = __importStar(require("./config-utils"));
const tracer_config_1 = require("./tracer-config"); const tracer_config_1 = require("./tracer-config");
const util = __importStar(require("./util")); const util = __importStar(require("./util"));
const util_1 = require("./util"); const util_1 = require("./util");
async function initCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolcache, logger) { async function initCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger) {
logger.startGroup("Setup CodeQL tools"); logger.startGroup("Setup CodeQL tools");
const { codeql, toolsVersion } = await (0, codeql_1.setupCodeQL)(toolsInput, apiDetails, tempDir, variant, bypassToolcache, logger, true); const { codeql, toolsVersion } = await (0, codeql_1.setupCodeQL)(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger, true);
await codeql.printVersion(); await codeql.printVersion();
logger.endGroup(); logger.endGroup();
return { codeql, toolsVersion }; return { codeql, toolsVersion };

View file

@ -1 +1 @@
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"} {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAE7B,yEAA2D;AAC3D,kEAAoD;AAEpD,gEAAkD;AAElD,qCAA2E;AAC3E,4DAA8C;AAI9C,mDAAwE;AACxE,6CAA+B;AAC/B,iCAA4C;AAErC,KAAK,UAAU,UAAU,CAC9B,UAA8B,EAC9B,UAA4B,EAC5B,OAAe,EACf,OAA2B,EAC3B,eAAwB,EACxB,iBAA2C,EAC3C,MAAc;IAEd,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,IAAA,oBAAW,EAChD,UAAU,EACV,UAAU,EACV,OAAO,EACP,OAAO,EACP,eAAe,EACf,iBAAiB,EACjB,MAAM,EACN,IAAI,CACL,CAAC;IACF,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;IAC5B,MAAM,CAAC,QAAQ,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;AAClC,CAAC;AAvBD,gCAuBC;AAEM,KAAK,UAAU,UAAU,CAC9B,cAAkC,EAClC,YAAgC,EAChC,UAA8B,EAC9B,eAAmC,EACnC,UAA8B,EAC9B,UAA8B,EAC9B,kBAA2B,EAC3B,SAAkB,EAClB,iBAAyB,EACzB,iBAAyB,EACzB,UAAyB,EACzB,OAAe,EACf,MAAc,EACd,aAAqB,EACrB,aAAiC,EACjC,UAAoC,EACpC,iBAAoC,EACpC,MAAc;IAEd,MAAM,CAAC,UAAU,CAAC,6BAA6B,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,UAAU,CACzC,cAAc,EACd,YAAY,EACZ,UAAU,EACV,eAAe,EACf,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,OAAO,EACP,MAAM,EACN,aAAa,EACb,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,MAAM,CACP,CAAC;IACF,aAAa,CAAC,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,MAAM,CAAC,QAAQ,EAAE,CAAC;IAClB,OAAO,MAAM,CAAC;AAChB,CAAC;AA5CD,gCA4CC;AAEM,KAAK,UAAU,OAAO,CAC3B,MAAc,EACd,MAA0B,EAC1B,UAAkB,EAClB,WAA+B,EAC/B,iBAAoC,EACpC,MAAc;IAEd,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAErD,IAAI;QACF,IAAI,MAAM,IAAA,yBAAkB,EAAC,MAAM,EAAE,mCAA0B,CAAC,EAAE;YAChE,0BAA0B;YAC1B,MAAM,MAAM,CAAC,mBAAmB,CAC9B,MAAM,EACN,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,MAAM,CACP,CAAC;SACH;aAAM;YACL,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE;gBACvC,yBAAyB;gBACzB,MAAM,MAAM,CAAC,YAAY,CACvB,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAC5C,QAAQ,EACR,UAAU,CACX,CAAC;aACH;SACF;KACF;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,YAAY,CAAC,CAAC,CAAC,CAAC;KACvB;IACD,OAAO,MAAM,IAAA,uCAAuB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACvD,CAAC;AAlCD,0BAkCC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY,CAAC,CAAM;;IAC1B,IAAI,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,EAAE;QACzB,OAAO,CAAC,CAAC;KACV;IAED;IACE,2BAA2B;IAC3B,CAAA,MAAA,CAAC,CAAC,OAAO,0CAAE,QAAQ,CAAC,8BAA8B,CAAC;SACnD,MAAA,CAAC,CAAC,OAAO,0CAAE,QAAQ,CAAC,uCAAuC,CAAC,CAAA,EAC5D;QACA,OAAO,IAAI,IAAI,CAAC,SAAS,CACvB,sDAAsD,CAAC,CAAC,OAAO,EAAE,CAClE,CAAC;KACH;IAED;IACE,+EAA+E;IAC/E,CAAA,MAAA,CAAC,CAAC,OAAO,0CAAE,QAAQ,CAAC,wCAAwC,CAAC;;QAC7D,gEAAgE;QAChE,MAAA,CAAC,CAAC,OAAO,0CAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAA,EAC1C;QACA,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;KACtC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAED,sEAAsE;AACtE,4EAA4E;AAC5E,4EAA4E;AAC5E,6EAA6E;AAC7E,+CAA+C;AACxC,KAAK,UAAU,mBAAmB,CACvC,WAA+B,EAC/B,YAAgC,EAChC,MAA0B,EAC1B,MAAc,EACd,YAA0B;IAE1B,IAAI,MAAc,CAAC;IACnB,IAAI,WAAW,KAAK,SAAS,EAAE;QAC7B,MAAM,GAAG;;;;;;;;;;;;uCAY0B,WAAW;;8BAEpB,WAAW;;;;;;;;gDAQO,CAAC;KAC9C;SAAM;QACL,oEAAoE;QACpE,mFAAmF;QACnF,+EAA+E;QAC/E,kFAAkF;QAClF,6EAA6E;QAC7E,oFAAoF;QACpF,6CAA6C;QAC7C,YAAY,GAAG,YAAY,IAAI,CAAC,CAAC;QACjC,MAAM,GAAG;;;;;;;;4BAQe,YAAY;;;;;;;;;;;;;;;;;;;;;gDAqBQ,CAAC;KAC9C;IAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACxE,EAAE,CAAC,aAAa,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAE3C,MAAM,IAAI,UAAU,CAAC,UAAU,CAC7B,MAAM,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,EACvC;QACE,kBAAkB;QAClB,QAAQ;QACR,OAAO;QACP,gBAAgB;QAChB,IAAI,CAAC,OAAO,CACV,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAC9B,OAAO,EACP,OAAO,EACP,YAAY,CACb;KACF,EACD,EAAE,GAAG,EAAE,EAAE,0BAA0B,EAAE,YAAY,CAAC,IAAI,EAAE,EAAE,CAC3D,CAAC,IAAI,EAAE,CAAC;AACX,CAAC;AA5FD,kDA4FC;AAEM,KAAK,UAAU,iBAAiB,CAAC,MAAc,EAAE,MAAc;IACpE,MAAM,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC;IAE/C,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAEjE,IAAI;QACF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE;YAChC,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE;gBACvE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,mBAAmB,CAAC;aAC9C,CAAC,CAAC,IAAI,EAAE,CAAC;SACX;aAAM;YACL,MAAM,IAAI,UAAU,CAAC,UAAU,CAC7B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAC7C,CAAC,IAAI,EAAE,CAAC;SACV;QACD,MAAM,MAAM,GAAG,0BAA0B,CAAC;QAC1C,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE;YAChC,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;gBAC/D,IAAI;gBACJ,IAAI;gBACJ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;aAC/B,CAAC,CAAC,IAAI,EAAE,CAAC;SACX;aAAM;YACL,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;gBACpE,IAAI;gBACJ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;aAC/B,CAAC,CAAC,IAAI,EAAE,CAAC;SACX;KACF;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,CAAC,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,OAAO,CACZ,gFAAgF,CAAC,IAAI;YACnF,qGAAqG;YACrG,oGAAoG;YACpG,iDAAiD,CACpD,CAAC;QACF,OAAO;KACR;IACD,MAAM,CAAC,QAAQ,EAAE,CAAC;AACpB,CAAC;AAzCD,8CAyCC"}

190
lib/setup-codeql.js generated
View file

@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.convertToSemVer = exports.getCodeQLURLVersion = exports.downloadCodeQL = exports.getCodeQLSource = exports.findCodeQLBundleTagDotcomOnly = exports.getCodeQLActionRepository = exports.CODEQL_DEFAULT_ACTION_REPOSITORY = void 0; exports.setupCodeQL = exports.getCodeQLURLVersion = exports.downloadCodeQL = exports.getCodeQLSource = exports.convertToSemVer = exports.getBundleTagNameFromUrl = exports.findCodeQLBundleTagDotcomOnly = exports.getCodeQLActionRepository = exports.CODEQL_DEFAULT_ACTION_REPOSITORY = void 0;
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
const path = __importStar(require("path")); const path = __importStar(require("path"));
const toolcache = __importStar(require("@actions/tool-cache")); const toolcache = __importStar(require("@actions/tool-cache"));
@ -34,7 +34,6 @@ const api = __importStar(require("./api-client"));
const defaults = __importStar(require("./defaults.json")); // Referenced from codeql-action-sync-tool! const defaults = __importStar(require("./defaults.json")); // Referenced from codeql-action-sync-tool!
const util = __importStar(require("./util")); const util = __importStar(require("./util"));
const util_1 = require("./util"); const util_1 = require("./util");
const CODEQL_BUNDLE_VERSION = defaults.bundleVersion;
exports.CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; exports.CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
function getCodeQLBundleName() { function getCodeQLBundleName() {
let platform; let platform;
@ -64,6 +63,7 @@ function getCodeQLActionRepository(logger) {
} }
exports.getCodeQLActionRepository = getCodeQLActionRepository; exports.getCodeQLActionRepository = getCodeQLActionRepository;
async function findCodeQLBundleTagDotcomOnly(cliVersion, logger) { async function findCodeQLBundleTagDotcomOnly(cliVersion, logger) {
logger.debug(`Trying to find the CodeQL bundle release for CLI version ${cliVersion}.`);
const apiClient = api.getApiClient(); const apiClient = api.getApiClient();
const codeQLActionRepository = getCodeQLActionRepository(logger); const codeQLActionRepository = getCodeQLActionRepository(logger);
const releases = await apiClient.paginate(apiClient.repos.listReleases, { const releases = await apiClient.paginate(apiClient.repos.listReleases, {
@ -91,7 +91,7 @@ async function findCodeQLBundleTagDotcomOnly(cliVersion, logger) {
throw new Error(`Failed to find a CodeQL bundle release for CLI version ${cliVersion}.`); throw new Error(`Failed to find a CodeQL bundle release for CLI version ${cliVersion}.`);
} }
exports.findCodeQLBundleTagDotcomOnly = findCodeQLBundleTagDotcomOnly; exports.findCodeQLBundleTagDotcomOnly = findCodeQLBundleTagDotcomOnly;
async function getCodeQLBundleDownloadURL(apiDetails, variant, logger) { async function getCodeQLBundleDownloadURL(tagName, apiDetails, variant, logger) {
const codeQLActionRepository = getCodeQLActionRepository(logger); const codeQLActionRepository = getCodeQLActionRepository(logger);
const potentialDownloadSources = [ const potentialDownloadSources = [
// This GitHub instance, and this Action. // This GitHub instance, and this Action.
@ -112,7 +112,7 @@ async function getCodeQLBundleDownloadURL(apiDetails, variant, logger) {
const release = await api const release = await api
.getApiClient() .getApiClient()
.request("GET /enterprise/code-scanning/codeql-bundle/find/{tag}", { .request("GET /enterprise/code-scanning/codeql-bundle/find/{tag}", {
tag: CODEQL_BUNDLE_VERSION, tag: tagName,
}); });
const assetID = release.data.assets[codeQLBundleName]; const assetID = release.data.assets[codeQLBundleName];
if (assetID !== undefined) { if (assetID !== undefined) {
@ -143,7 +143,7 @@ async function getCodeQLBundleDownloadURL(apiDetails, variant, logger) {
const release = await api.getApiClient().repos.getReleaseByTag({ const release = await api.getApiClient().repos.getReleaseByTag({
owner: repositoryOwner, owner: repositoryOwner,
repo: repositoryName, repo: repositoryName,
tag: CODEQL_BUNDLE_VERSION, tag: tagName,
}); });
for (const asset of release.data.assets) { for (const asset of release.data.assets) {
if (asset.name === codeQLBundleName) { if (asset.name === codeQLBundleName) {
@ -156,10 +156,67 @@ async function getCodeQLBundleDownloadURL(apiDetails, variant, logger) {
logger.info(`Looked for CodeQL bundle in ${downloadSource[1]} on ${downloadSource[0]} but got error ${e}.`); logger.info(`Looked for CodeQL bundle in ${downloadSource[1]} on ${downloadSource[0]} but got error ${e}.`);
} }
} }
return `https://github.com/${exports.CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${CODEQL_BUNDLE_VERSION}/${codeQLBundleName}`; return `https://github.com/${exports.CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${codeQLBundleName}`;
} }
async function getCodeQLSource(toolsInput, bypassToolcache, apiDetails, variant, logger) { function getBundleTagNameFromUrl(url) {
var _a; const match = url.match(/\/codeql-bundle-(.*)\//);
if (match === null || match.length < 2) {
throw new Error(`Malformed tools url: ${url}. Tag name could not be inferred`);
}
return match[1];
}
exports.getBundleTagNameFromUrl = getBundleTagNameFromUrl;
function convertToSemVer(version, logger) {
if (!semver.valid(version)) {
logger.debug(`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`);
version = `0.0.0-${version}`;
}
const s = semver.clean(version);
if (!s) {
throw new Error(`Bundle version ${version} is not in SemVer format.`);
}
return s;
}
exports.convertToSemVer = convertToSemVer;
async function getOrFindBundleTagName(version, logger) {
if (version.variant === util.GitHubVariant.DOTCOM) {
return await findCodeQLBundleTagDotcomOnly(version.cliVersion, logger);
}
else {
return version.tagName;
}
}
/**
* Look for a version of the CodeQL tools in the cache which could override the requested CLI version.
*/
async function findOverridingToolsInCache(requestedCliVersion, logger) {
const candidates = toolcache
.findAllVersions("CodeQL")
.filter(util_1.isGoodVersion)
.map((version) => ({
folder: toolcache.find("CodeQL", version),
version,
}))
.filter(({ folder }) => fs.existsSync(path.join(folder, "pinned-version")));
if (candidates.length === 1) {
const candidate = candidates[0];
logger.debug(`CodeQL tools version ${candidate.version} in toolcache overriding version ${requestedCliVersion}.`);
return {
codeqlFolder: candidate.folder,
sourceType: "toolcache",
toolsVersion: candidate.version,
};
}
else if (candidates.length === 0) {
logger.debug("Did not find any candidate pinned versions of the CodeQL tools in the toolcache.");
}
else {
logger.debug("Could not use CodeQL tools from the toolcache since more than one candidate pinned " +
"version was found in the toolcache.");
}
return undefined;
}
async function getCodeQLSource(toolsInput, bypassToolcache, defaultCliVersion, apiDetails, variant, logger) {
if (toolsInput && toolsInput !== "latest" && !toolsInput.startsWith("http")) { if (toolsInput && toolsInput !== "latest" && !toolsInput.startsWith("http")) {
return { return {
codeqlTarPath: toolsInput, codeqlTarPath: toolsInput,
@ -177,46 +234,77 @@ async function getCodeQLSource(toolsInput, bypassToolcache, apiDetails, variant,
// allows us to quickly rollback a broken bundle that has made its way // allows us to quickly rollback a broken bundle that has made its way
// into the toolcache. // into the toolcache.
toolsInput === undefined && bypassToolcache toolsInput === undefined && bypassToolcache
? "a specific version of CodeQL was not requested and the bypass toolcache feature is enabled" ? "a specific version of the CodeQL tools was not requested and the bypass toolcache feature is enabled"
: undefined; : undefined;
const forceLatest = forceLatestReason !== undefined; const forceLatest = forceLatestReason !== undefined;
if (forceLatest) { if (forceLatest) {
logger.debug(`Forcing the latest version of the CodeQL tools since ${forceLatestReason}.`); logger.debug(`Forcing the latest version of the CodeQL tools since ${forceLatestReason}.`);
} }
const codeqlURL = forceLatest ? undefined : toolsInput; /**
const requestedSemVer = convertToSemVer(getCodeQLURLVersion(codeqlURL || `/${CODEQL_BUNDLE_VERSION}/`), logger); * The requested version is:
*
* 1. The one in `defaults.json`, if forceLatest is true.
* 2. The version specified by the tools input URL, if one was provided.
* 3. The default CLI version, otherwise.
* We include a `variant` property to let us verify using the type system that
* `tagName` is only undefined when the variant is Dotcom. This lets us ensure
* that we can always compute `tagName`, either by using the existing tag name
* on enterprise instances, or safely calling `findCodeQLBundleTagDotcomOnly`
* on Dotcom.
*/
const requestedVersion = forceLatest
? // case 1
{
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant,
}
: toolsInput !== undefined
? // case 2
{
cliVersion: convertToSemVer(getBundleTagNameFromUrl(toolsInput), logger),
tagName: getBundleTagNameFromUrl(toolsInput),
url: toolsInput,
variant,
}
: // case 3
defaultCliVersion;
// If we find the specified version, we always use that. // If we find the specified version, we always use that.
const codeqlFolder = toolcache.find("CodeQL", requestedSemVer); let codeqlFolder = toolcache.find("CodeQL", requestedVersion.cliVersion);
let tagName = requestedVersion["tagName"];
if (!codeqlFolder && !requestedVersion.cliVersion.startsWith("0.0.0")) {
// Fall back to accepting a `0.0.0-<tagName>` version if we didn't find the
// `x.y.z` version. This is to support old versions of the toolcache.
tagName =
tagName || (await getOrFindBundleTagName(requestedVersion, logger));
const fallbackVersion = convertToSemVer(tagName, logger);
logger.debug(`Computed a fallback toolcache version number of ${fallbackVersion} for CodeQL tools version ${requestedVersion.cliVersion}.`);
codeqlFolder = toolcache.find("CodeQL", fallbackVersion);
}
if (codeqlFolder) { if (codeqlFolder) {
return { return {
codeqlFolder, codeqlFolder,
sourceType: "toolcache", sourceType: "toolcache",
toolsVersion: requestedSemVer, toolsVersion: requestedVersion.cliVersion,
}; };
} }
// If we don't find the requested version, in some cases we may allow a logger.debug(`Did not find CodeQL tools version ${requestedVersion.cliVersion} in the toolcache.`);
// If we don't find the requested version on Enterprise, we may allow a
// different version to save download time if the version hasn't been // different version to save download time if the version hasn't been
// specified explicitly (in which case we always honor it). // specified explicitly (in which case we always honor it).
if (!codeqlURL && !forceLatest) { if (variant !== util.GitHubVariant.DOTCOM && !forceLatest && !toolsInput) {
const codeqlVersions = toolcache.findAllVersions("CodeQL"); const result = await findOverridingToolsInCache(requestedVersion.cliVersion, logger);
if (codeqlVersions.length === 1 && (0, util_1.isGoodVersion)(codeqlVersions[0])) { if (result !== undefined) {
const tmpCodeqlFolder = toolcache.find("CodeQL", codeqlVersions[0]); return result;
if (fs.existsSync(path.join(tmpCodeqlFolder, "pinned-version"))) {
logger.debug(`CodeQL in cache overriding the default ${CODEQL_BUNDLE_VERSION}`);
return {
codeqlFolder: tmpCodeqlFolder,
sourceType: "toolcache",
toolsVersion: codeqlVersions[0],
};
}
} }
} }
return { return {
codeqlURL: codeqlURL || codeqlURL: requestedVersion["url"] ||
(await getCodeQLBundleDownloadURL(apiDetails, variant, logger)), (await getCodeQLBundleDownloadURL(tagName || (await getOrFindBundleTagName(requestedVersion, logger)), apiDetails, variant, logger)),
semanticVersion: requestedSemVer, semanticVersion: requestedVersion.cliVersion,
sourceType: "download", sourceType: "download",
toolsVersion: ((_a = semver.prerelease(requestedSemVer)) === null || _a === void 0 ? void 0 : _a.join(".")) || requestedSemVer, toolsVersion: requestedVersion.cliVersion,
}; };
} }
exports.getCodeQLSource = getCodeQLSource; exports.getCodeQLSource = getCodeQLSource;
@ -257,16 +345,38 @@ function getCodeQLURLVersion(url) {
return match[1]; return match[1];
} }
exports.getCodeQLURLVersion = getCodeQLURLVersion; exports.getCodeQLURLVersion = getCodeQLURLVersion;
function convertToSemVer(version, logger) { /**
if (!semver.valid(version)) { * Set up CodeQL CLI access.
logger.debug(`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`); *
version = `0.0.0-${version}`; * @param toolsInput
* @param apiDetails
* @param tempDir
* @param variant
* @param bypassToolcache
* @param defaultCliVersion
* @param logger
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
* version requirement. Must be set to true outside tests.
* @returns a { CodeQL, toolsVersion } object.
*/
async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger) {
const source = await getCodeQLSource(toolsInput, bypassToolcache, defaultCliVersion, apiDetails, variant, logger);
let codeqlFolder;
switch (source.sourceType) {
case "local":
codeqlFolder = await toolcache.extractTar(source.codeqlTarPath);
break;
case "toolcache":
codeqlFolder = source.codeqlFolder;
logger.debug(`CodeQL found in cache ${codeqlFolder}`);
break;
case "download":
codeqlFolder = await downloadCodeQL(source.codeqlURL, source.semanticVersion, apiDetails, tempDir, logger);
break;
default:
util.assertNever(source);
} }
const s = semver.clean(version); return { codeqlFolder, toolsVersion: source.toolsVersion };
if (!s) {
throw new Error(`Bundle version ${version} is not in SemVer format.`);
}
return s;
} }
exports.convertToSemVer = convertToSemVer; exports.setupCodeQL = setupCodeQL;
//# sourceMappingURL=setup-codeql.js.map //# sourceMappingURL=setup-codeql.js.map

File diff suppressed because one or more lines are too long

View file

@ -15,7 +15,11 @@ import { GitHubApiDetails } from "./api-client";
import * as codeql from "./codeql"; import * as codeql from "./codeql";
import { AugmentationProperties, Config } from "./config-utils"; import { AugmentationProperties, Config } from "./config-utils";
import * as defaults from "./defaults.json"; // Referenced from codeql-action-sync-tool! import * as defaults from "./defaults.json"; // Referenced from codeql-action-sync-tool!
import { Feature, featureConfig } from "./feature-flags"; import {
CodeQLDefaultVersionInfo,
Feature,
featureConfig,
} from "./feature-flags";
import { Language } from "./languages"; import { Language } from "./languages";
import { getRunnerLogger } from "./logging"; import { getRunnerLogger } from "./logging";
import { setupTests, createFeatures, setupActionsVars } from "./testing-utils"; import { setupTests, createFeatures, setupActionsVars } from "./testing-utils";
@ -36,6 +40,11 @@ const sampleGHAEApiDetails = {
apiURL: "https://example.githubenterprise.com/api/v3", apiURL: "https://example.githubenterprise.com/api/v3",
}; };
const SAMPLE_DEFAULT_CLI_VERSION: CodeQLDefaultVersionInfo = {
cliVersion: "2.0.0",
variant: util.GitHubVariant.DOTCOM,
};
let stubConfig: Config; let stubConfig: Config;
test.beforeEach(() => { test.beforeEach(() => {
@ -125,6 +134,7 @@ async function installIntoToolcache({
tmpDir, tmpDir,
util.GitHubVariant.DOTCOM, util.GitHubVariant.DOTCOM,
false, false,
SAMPLE_DEFAULT_CLI_VERSION,
getRunnerLogger(true), getRunnerLogger(true),
false false
); );
@ -149,11 +159,12 @@ test("downloads and caches explicitly requested bundles that aren't in the toolc
tmpDir, tmpDir,
util.GitHubVariant.DOTCOM, util.GitHubVariant.DOTCOM,
false, false,
SAMPLE_DEFAULT_CLI_VERSION,
getRunnerLogger(true), getRunnerLogger(true),
false false
); );
t.assert(toolcache.find("CodeQL", `0.0.0-${version}`)); t.assert(toolcache.find("CodeQL", `0.0.0-${version}`));
t.is(result.toolsVersion, version); t.is(result.toolsVersion, `0.0.0-${version}`);
} }
t.is(toolcache.findAllVersions("CodeQL").length, 2); t.is(toolcache.findAllVersions("CodeQL").length, 2);
@ -179,71 +190,81 @@ test("downloads an explicitly requested bundle even if a different version is ca
tmpDir, tmpDir,
util.GitHubVariant.DOTCOM, util.GitHubVariant.DOTCOM,
false, false,
SAMPLE_DEFAULT_CLI_VERSION,
getRunnerLogger(true), getRunnerLogger(true),
false false
); );
t.assert(toolcache.find("CodeQL", "0.0.0-20200610")); t.assert(toolcache.find("CodeQL", "0.0.0-20200610"));
t.deepEqual(result.toolsVersion, "20200610"); t.deepEqual(result.toolsVersion, "0.0.0-20200610");
}); });
}); });
test("uses a cached bundle when no tools input is given", async (t) => { for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
await util.withTmpDir(async (tmpDir) => { test(`uses a cached bundle when no tools input is given on ${util.GitHubVariant[variant]}`, async (t) => {
setupActionsVars(tmpDir, tmpDir); await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
await installIntoToolcache({ await installIntoToolcache({
tagName: "codeql-bundle-20200601", tagName: "codeql-bundle-20200601",
isPinned: true, isPinned: true,
tmpDir, tmpDir,
});
const result = await codeql.setupCodeQL(
undefined,
sampleApiDetails,
tmpDir,
variant,
false,
{
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant,
},
getRunnerLogger(true),
false
);
t.deepEqual(result.toolsVersion, "0.0.0-20200601");
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 1);
}); });
const result = await codeql.setupCodeQL(
undefined,
sampleApiDetails,
tmpDir,
util.GitHubVariant.DOTCOM,
false,
getRunnerLogger(true),
false
);
t.deepEqual(result.toolsVersion, "0.0.0-20200601");
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 1);
}); });
});
test("downloads bundle if only an unpinned version is cached", async (t) => { test(`downloads bundle if only an unpinned version is cached on ${util.GitHubVariant[variant]}`, async (t) => {
await util.withTmpDir(async (tmpDir) => { await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir); setupActionsVars(tmpDir, tmpDir);
await installIntoToolcache({ await installIntoToolcache({
tagName: "codeql-bundle-20200601", tagName: "codeql-bundle-20200601",
isPinned: false, isPinned: false,
tmpDir, tmpDir,
});
await mockDownloadApi({
tagName: defaults.bundleVersion,
});
const result = await codeql.setupCodeQL(
undefined,
sampleApiDetails,
tmpDir,
variant,
false,
{
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant,
},
getRunnerLogger(true),
false
);
t.deepEqual(result.toolsVersion, defaults.cliVersion);
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 2);
}); });
await mockDownloadApi({
tagName: defaults.bundleVersion,
});
const result = await codeql.setupCodeQL(
undefined,
sampleApiDetails,
tmpDir,
util.GitHubVariant.DOTCOM,
false,
getRunnerLogger(true),
false
);
t.deepEqual(
result.toolsVersion,
defaults.bundleVersion.replace("codeql-bundle-", "")
);
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 2);
}); });
}); }
test('downloads bundle if "latest" tools specified but not cached', async (t) => { test('downloads bundle if "latest" tools specified but not cached', async (t) => {
await util.withTmpDir(async (tmpDir) => { await util.withTmpDir(async (tmpDir) => {
@ -264,69 +285,17 @@ test('downloads bundle if "latest" tools specified but not cached', async (t) =>
tmpDir, tmpDir,
util.GitHubVariant.DOTCOM, util.GitHubVariant.DOTCOM,
false, false,
SAMPLE_DEFAULT_CLI_VERSION,
getRunnerLogger(true), getRunnerLogger(true),
false false
); );
t.deepEqual( t.deepEqual(result.toolsVersion, defaults.cliVersion);
result.toolsVersion,
defaults.bundleVersion.replace("codeql-bundle-", "")
);
const cachedVersions = toolcache.findAllVersions("CodeQL"); const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, 2); t.is(cachedVersions.length, 2);
}); });
}); });
const TOOLCACHE_BYPASS_TEST_CASES: Array<
[boolean, string | undefined, boolean]
> = [
[true, undefined, true],
[false, undefined, false],
[
true,
"https://github.com/github/codeql-action/releases/download/codeql-bundle-20200601/codeql-bundle.tar.gz",
false,
],
];
for (const [
isFeatureEnabled,
toolsInput,
shouldToolcacheBeBypassed,
] of TOOLCACHE_BYPASS_TEST_CASES) {
test(`download codeql bundle ${
shouldToolcacheBeBypassed ? "bypasses" : "does not bypass"
} toolcache when feature ${
isFeatureEnabled ? "enabled" : "disabled"
} and tools: ${toolsInput} passed`, async (t) => {
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
await installIntoToolcache({
tagName: "codeql-bundle-20200601",
isPinned: true,
tmpDir,
});
await mockDownloadApi({
tagName: defaults.bundleVersion,
});
await codeql.setupCodeQL(
toolsInput,
sampleApiDetails,
tmpDir,
util.GitHubVariant.DOTCOM,
isFeatureEnabled,
getRunnerLogger(true),
false
);
const cachedVersions = toolcache.findAllVersions("CodeQL");
t.is(cachedVersions.length, shouldToolcacheBeBypassed ? 2 : 1);
});
});
}
test("download codeql bundle from github ae endpoint", async (t) => { test("download codeql bundle from github ae endpoint", async (t) => {
await util.withTmpDir(async (tmpDir) => { await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir); setupActionsVars(tmpDir, tmpDir);
@ -391,6 +360,11 @@ test("download codeql bundle from github ae endpoint", async (t) => {
tmpDir, tmpDir,
util.GitHubVariant.GHAE, util.GitHubVariant.GHAE,
false, false,
{
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant: util.GitHubVariant.GHAE,
},
getRunnerLogger(true), getRunnerLogger(true),
false false
); );

View file

@ -2,24 +2,22 @@ import * as fs from "fs";
import * as path from "path"; 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 yaml from "js-yaml"; import * as yaml from "js-yaml";
import { getOptionalInput } from "./actions-util"; import { getOptionalInput } from "./actions-util";
import * as api from "./api-client"; import * as api from "./api-client";
import { Config } from "./config-utils"; import { Config } from "./config-utils";
import { errorMatchers } from "./error-matcher"; import { errorMatchers } from "./error-matcher";
import { FeatureEnablement } from "./feature-flags"; import { CodeQLDefaultVersionInfo, FeatureEnablement } from "./feature-flags";
import { isTracedLanguage, Language } from "./languages"; import { isTracedLanguage, Language } from "./languages";
import { Logger } from "./logging"; import { Logger } from "./logging";
import { downloadCodeQL, getCodeQLSource } from "./setup-codeql"; import * as setupCodeql from "./setup-codeql";
import { toolrunnerErrorCatcher } from "./toolrunner-error-catcher"; import { toolrunnerErrorCatcher } from "./toolrunner-error-catcher";
import { import {
getTrapCachingExtractorConfigArgs, getTrapCachingExtractorConfigArgs,
getTrapCachingExtractorConfigArgsForLang, getTrapCachingExtractorConfigArgsForLang,
} from "./trap-caching"; } from "./trap-caching";
import * as util from "./util"; import * as util from "./util";
import { assertNever } from "./util";
type Options = Array<string | number | boolean>; type Options = Array<string | number | boolean>;
@ -287,6 +285,7 @@ export const CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = "2.10.3";
* @param tempDir * @param tempDir
* @param variant * @param variant
* @param bypassToolcache * @param bypassToolcache
* @param defaultCliVersion
* @param logger * @param logger
* @param checkVersion Whether to check that CodeQL CLI meets the minimum * @param checkVersion Whether to check that CodeQL CLI meets the minimum
* version requirement. Must be set to true outside tests. * version requirement. Must be set to true outside tests.
@ -298,41 +297,20 @@ export async function setupCodeQL(
tempDir: string, tempDir: string,
variant: util.GitHubVariant, variant: util.GitHubVariant,
bypassToolcache: boolean, bypassToolcache: boolean,
defaultCliVersion: CodeQLDefaultVersionInfo,
logger: Logger, logger: Logger,
checkVersion: boolean checkVersion: boolean
): Promise<{ codeql: CodeQL; toolsVersion: string }> { ): Promise<{ codeql: CodeQL; toolsVersion: string }> {
try { try {
const source = await getCodeQLSource( const { codeqlFolder, toolsVersion } = await setupCodeql.setupCodeQL(
toolsInput, toolsInput,
bypassToolcache,
apiDetails, apiDetails,
tempDir,
variant, variant,
bypassToolcache,
defaultCliVersion,
logger logger
); );
let codeqlFolder: string;
switch (source.sourceType) {
case "local":
codeqlFolder = await toolcache.extractTar(source.codeqlTarPath);
break;
case "toolcache":
codeqlFolder = source.codeqlFolder;
logger.debug(`CodeQL found in cache ${codeqlFolder}`);
break;
case "download":
codeqlFolder = await downloadCodeQL(
source.codeqlURL,
source.semanticVersion,
apiDetails,
tempDir,
logger
);
break;
default:
assertNever(source);
}
let codeqlCmd = path.join(codeqlFolder, "codeql", "codeql"); let codeqlCmd = path.join(codeqlFolder, "codeql", "codeql");
if (process.platform === "win32") { if (process.platform === "win32") {
codeqlCmd += ".exe"; codeqlCmd += ".exe";
@ -341,7 +319,7 @@ export async function setupCodeQL(
} }
cachedCodeQL = await getCodeQLForCmd(codeqlCmd, checkVersion); cachedCodeQL = await getCodeQLForCmd(codeqlCmd, checkVersion);
return { codeql: cachedCodeQL, toolsVersion: source.toolsVersion }; return { codeql: cachedCodeQL, toolsVersion };
} catch (e) { } catch (e) {
logger.error(e instanceof Error ? e : new Error(String(e))); logger.error(e instanceof Error ? e : new Error(String(e)));
throw new Error("Unable to download and extract CodeQL CLI"); throw new Error("Unable to download and extract CodeQL CLI");

View file

@ -182,6 +182,9 @@ async function run() {
return; return;
} }
const defaultCliVersion = await features.getDefaultCliVersion(
gitHubVersion.type
);
const initCodeQLResult = await initCodeQL( const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"), getOptionalInput("tools"),
apiDetails, apiDetails,
@ -194,6 +197,7 @@ async function run() {
repositoryNwo, repositoryNwo,
logger logger
), ),
defaultCliVersion,
logger logger
); );
codeql = initCodeQLResult.codeql; codeql = initCodeQLResult.codeql;

View file

@ -8,7 +8,7 @@ import * as analysisPaths from "./analysis-paths";
import { GitHubApiCombinedDetails, GitHubApiDetails } from "./api-client"; import { GitHubApiCombinedDetails, GitHubApiDetails } from "./api-client";
import { CodeQL, CODEQL_VERSION_NEW_TRACING, setupCodeQL } from "./codeql"; import { CodeQL, CODEQL_VERSION_NEW_TRACING, setupCodeQL } from "./codeql";
import * as configUtils from "./config-utils"; import * as configUtils from "./config-utils";
import { FeatureEnablement } from "./feature-flags"; import { CodeQLDefaultVersionInfo, FeatureEnablement } from "./feature-flags";
import { Logger } from "./logging"; import { Logger } from "./logging";
import { RepositoryNwo } from "./repository"; import { RepositoryNwo } from "./repository";
import { TracerConfig, getCombinedTracerConfig } from "./tracer-config"; import { TracerConfig, getCombinedTracerConfig } from "./tracer-config";
@ -21,6 +21,7 @@ export async function initCodeQL(
tempDir: string, tempDir: string,
variant: util.GitHubVariant, variant: util.GitHubVariant,
bypassToolcache: boolean, bypassToolcache: boolean,
defaultCliVersion: CodeQLDefaultVersionInfo,
logger: Logger logger: Logger
): Promise<{ codeql: CodeQL; toolsVersion: string }> { ): Promise<{ codeql: CodeQL; toolsVersion: string }> {
logger.startGroup("Setup CodeQL tools"); logger.startGroup("Setup CodeQL tools");
@ -30,6 +31,7 @@ export async function initCodeQL(
tempDir, tempDir,
variant, variant,
bypassToolcache, bypassToolcache,
defaultCliVersion,
logger, logger,
true true
); );

View file

@ -10,11 +10,11 @@ import { v4 as uuidV4 } from "uuid";
import { isRunningLocalAction } from "./actions-util"; import { isRunningLocalAction } from "./actions-util";
import * as api from "./api-client"; import * as api from "./api-client";
import * as defaults from "./defaults.json"; // Referenced from codeql-action-sync-tool! import * as defaults from "./defaults.json"; // Referenced from codeql-action-sync-tool!
import { CodeQLDefaultVersionInfo } from "./feature-flags";
import { Logger } from "./logging"; import { Logger } from "./logging";
import * as util from "./util"; import * as util from "./util";
import { isGoodVersion } from "./util"; import { isGoodVersion } from "./util";
const CODEQL_BUNDLE_VERSION = defaults.bundleVersion;
export const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; export const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
function getCodeQLBundleName(): string { function getCodeQLBundleName(): string {
@ -49,6 +49,9 @@ export async function findCodeQLBundleTagDotcomOnly(
cliVersion: string, cliVersion: string,
logger: Logger logger: Logger
): Promise<string> { ): Promise<string> {
logger.debug(
`Trying to find the CodeQL bundle release for CLI version ${cliVersion}.`
);
const apiClient = api.getApiClient(); const apiClient = api.getApiClient();
const codeQLActionRepository = getCodeQLActionRepository(logger); const codeQLActionRepository = getCodeQLActionRepository(logger);
const releases = await apiClient.paginate(apiClient.repos.listReleases, { const releases = await apiClient.paginate(apiClient.repos.listReleases, {
@ -85,6 +88,7 @@ export async function findCodeQLBundleTagDotcomOnly(
} }
async function getCodeQLBundleDownloadURL( async function getCodeQLBundleDownloadURL(
tagName: string,
apiDetails: api.GitHubApiDetails, apiDetails: api.GitHubApiDetails,
variant: util.GitHubVariant, variant: util.GitHubVariant,
logger: Logger logger: Logger
@ -111,7 +115,7 @@ async function getCodeQLBundleDownloadURL(
const release = await api const release = await api
.getApiClient() .getApiClient()
.request("GET /enterprise/code-scanning/codeql-bundle/find/{tag}", { .request("GET /enterprise/code-scanning/codeql-bundle/find/{tag}", {
tag: CODEQL_BUNDLE_VERSION, tag: tagName,
}); });
const assetID = release.data.assets[codeQLBundleName]; const assetID = release.data.assets[codeQLBundleName];
if (assetID !== undefined) { if (assetID !== undefined) {
@ -153,7 +157,7 @@ async function getCodeQLBundleDownloadURL(
const release = await api.getApiClient().repos.getReleaseByTag({ const release = await api.getApiClient().repos.getReleaseByTag({
owner: repositoryOwner, owner: repositoryOwner,
repo: repositoryName, repo: repositoryName,
tag: CODEQL_BUNDLE_VERSION, tag: tagName,
}); });
for (const asset of release.data.assets) { for (const asset of release.data.assets) {
if (asset.name === codeQLBundleName) { if (asset.name === codeQLBundleName) {
@ -169,7 +173,33 @@ async function getCodeQLBundleDownloadURL(
); );
} }
} }
return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${CODEQL_BUNDLE_VERSION}/${codeQLBundleName}`; return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${codeQLBundleName}`;
}
export function getBundleTagNameFromUrl(url: string): string {
const match = url.match(/\/codeql-bundle-(.*)\//);
if (match === null || match.length < 2) {
throw new Error(
`Malformed tools url: ${url}. Tag name could not be inferred`
);
}
return match[1];
}
export function convertToSemVer(version: string, logger: Logger): string {
if (!semver.valid(version)) {
logger.debug(
`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`
);
version = `0.0.0-${version}`;
}
const s = semver.clean(version);
if (!s) {
throw new Error(`Bundle version ${version} is not in SemVer format.`);
}
return s;
} }
type CodeQLToolsSource = type CodeQLToolsSource =
@ -186,9 +216,60 @@ type CodeQLToolsSource =
toolsVersion: string; toolsVersion: string;
}; };
async function getOrFindBundleTagName(
version: CodeQLDefaultVersionInfo,
logger: Logger
): Promise<string> {
if (version.variant === util.GitHubVariant.DOTCOM) {
return await findCodeQLBundleTagDotcomOnly(version.cliVersion, logger);
} else {
return version.tagName;
}
}
/**
* Look for a version of the CodeQL tools in the cache which could override the requested CLI version.
*/
async function findOverridingToolsInCache(
requestedCliVersion: string,
logger: Logger
): Promise<CodeQLToolsSource | undefined> {
const candidates = toolcache
.findAllVersions("CodeQL")
.filter(isGoodVersion)
.map((version) => ({
folder: toolcache.find("CodeQL", version),
version,
}))
.filter(({ folder }) => fs.existsSync(path.join(folder, "pinned-version")));
if (candidates.length === 1) {
const candidate = candidates[0];
logger.debug(
`CodeQL tools version ${candidate.version} in toolcache overriding version ${requestedCliVersion}.`
);
return {
codeqlFolder: candidate.folder,
sourceType: "toolcache",
toolsVersion: candidate.version,
};
} else if (candidates.length === 0) {
logger.debug(
"Did not find any candidate pinned versions of the CodeQL tools in the toolcache."
);
} else {
logger.debug(
"Could not use CodeQL tools from the toolcache since more than one candidate pinned " +
"version was found in the toolcache."
);
}
return undefined;
}
export async function getCodeQLSource( export async function getCodeQLSource(
toolsInput: string | undefined, toolsInput: string | undefined,
bypassToolcache: boolean, bypassToolcache: boolean,
defaultCliVersion: CodeQLDefaultVersionInfo,
apiDetails: api.GitHubApiDetails, apiDetails: api.GitHubApiDetails,
variant: util.GitHubVariant, variant: util.GitHubVariant,
logger: Logger logger: Logger
@ -211,7 +292,7 @@ export async function getCodeQLSource(
// allows us to quickly rollback a broken bundle that has made its way // allows us to quickly rollback a broken bundle that has made its way
// into the toolcache. // into the toolcache.
toolsInput === undefined && bypassToolcache toolsInput === undefined && bypassToolcache
? "a specific version of CodeQL was not requested and the bypass toolcache feature is enabled" ? "a specific version of the CodeQL tools was not requested and the bypass toolcache feature is enabled"
: undefined; : undefined;
const forceLatest = forceLatestReason !== undefined; const forceLatest = forceLatestReason !== undefined;
if (forceLatest) { if (forceLatest) {
@ -220,50 +301,92 @@ export async function getCodeQLSource(
); );
} }
const codeqlURL = forceLatest ? undefined : toolsInput; /**
const requestedSemVer = convertToSemVer( * The requested version is:
getCodeQLURLVersion(codeqlURL || `/${CODEQL_BUNDLE_VERSION}/`), *
logger * 1. The one in `defaults.json`, if forceLatest is true.
); * 2. The version specified by the tools input URL, if one was provided.
* 3. The default CLI version, otherwise.
* We include a `variant` property to let us verify using the type system that
* `tagName` is only undefined when the variant is Dotcom. This lets us ensure
* that we can always compute `tagName`, either by using the existing tag name
* on enterprise instances, or safely calling `findCodeQLBundleTagDotcomOnly`
* on Dotcom.
*/
const requestedVersion = forceLatest
? // case 1
{
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant,
}
: toolsInput !== undefined
? // case 2
{
cliVersion: convertToSemVer(
getBundleTagNameFromUrl(toolsInput),
logger
),
tagName: getBundleTagNameFromUrl(toolsInput),
url: toolsInput,
variant,
}
: // case 3
defaultCliVersion;
// If we find the specified version, we always use that. // If we find the specified version, we always use that.
const codeqlFolder = toolcache.find("CodeQL", requestedSemVer); let codeqlFolder = toolcache.find("CodeQL", requestedVersion.cliVersion);
let tagName: string | undefined = requestedVersion["tagName"];
if (!codeqlFolder && !requestedVersion.cliVersion.startsWith("0.0.0")) {
// Fall back to accepting a `0.0.0-<tagName>` version if we didn't find the
// `x.y.z` version. This is to support old versions of the toolcache.
tagName =
tagName || (await getOrFindBundleTagName(requestedVersion, logger));
const fallbackVersion = convertToSemVer(tagName, logger);
logger.debug(
`Computed a fallback toolcache version number of ${fallbackVersion} for CodeQL tools version ${requestedVersion.cliVersion}.`
);
codeqlFolder = toolcache.find("CodeQL", fallbackVersion);
}
if (codeqlFolder) { if (codeqlFolder) {
return { return {
codeqlFolder, codeqlFolder,
sourceType: "toolcache", sourceType: "toolcache",
toolsVersion: requestedSemVer, toolsVersion: requestedVersion.cliVersion,
}; };
} }
logger.debug(
`Did not find CodeQL tools version ${requestedVersion.cliVersion} in the toolcache.`
);
// If we don't find the requested version, in some cases we may allow a // If we don't find the requested version on Enterprise, we may allow a
// different version to save download time if the version hasn't been // different version to save download time if the version hasn't been
// specified explicitly (in which case we always honor it). // specified explicitly (in which case we always honor it).
if (!codeqlURL && !forceLatest) { if (variant !== util.GitHubVariant.DOTCOM && !forceLatest && !toolsInput) {
const codeqlVersions = toolcache.findAllVersions("CodeQL"); const result = await findOverridingToolsInCache(
if (codeqlVersions.length === 1 && isGoodVersion(codeqlVersions[0])) { requestedVersion.cliVersion,
const tmpCodeqlFolder = toolcache.find("CodeQL", codeqlVersions[0]); logger
if (fs.existsSync(path.join(tmpCodeqlFolder, "pinned-version"))) { );
logger.debug( if (result !== undefined) {
`CodeQL in cache overriding the default ${CODEQL_BUNDLE_VERSION}` return result;
);
return {
codeqlFolder: tmpCodeqlFolder,
sourceType: "toolcache",
toolsVersion: codeqlVersions[0],
};
}
} }
} }
return { return {
codeqlURL: codeqlURL:
codeqlURL || requestedVersion["url"] ||
(await getCodeQLBundleDownloadURL(apiDetails, variant, logger)), (await getCodeQLBundleDownloadURL(
semanticVersion: requestedSemVer, tagName || (await getOrFindBundleTagName(requestedVersion, logger)),
apiDetails,
variant,
logger
)),
semanticVersion: requestedVersion.cliVersion,
sourceType: "download", sourceType: "download",
toolsVersion: toolsVersion: requestedVersion.cliVersion,
semver.prerelease(requestedSemVer)?.join(".") || requestedSemVer,
}; };
} }
@ -322,18 +445,58 @@ export function getCodeQLURLVersion(url: string): string {
return match[1]; return match[1];
} }
export function convertToSemVer(version: string, logger: Logger): string { /**
if (!semver.valid(version)) { * Set up CodeQL CLI access.
logger.debug( *
`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.` * @param toolsInput
); * @param apiDetails
version = `0.0.0-${version}`; * @param tempDir
} * @param variant
* @param bypassToolcache
* @param defaultCliVersion
* @param logger
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
* version requirement. Must be set to true outside tests.
* @returns a { CodeQL, toolsVersion } object.
*/
export async function setupCodeQL(
toolsInput: string | undefined,
apiDetails: api.GitHubApiDetails,
tempDir: string,
variant: util.GitHubVariant,
bypassToolcache: boolean,
defaultCliVersion: CodeQLDefaultVersionInfo,
logger: Logger
): Promise<{ codeqlFolder: string; toolsVersion: string }> {
const source = await getCodeQLSource(
toolsInput,
bypassToolcache,
defaultCliVersion,
apiDetails,
variant,
logger
);
const s = semver.clean(version); let codeqlFolder: string;
if (!s) { switch (source.sourceType) {
throw new Error(`Bundle version ${version} is not in SemVer format.`); case "local":
codeqlFolder = await toolcache.extractTar(source.codeqlTarPath);
break;
case "toolcache":
codeqlFolder = source.codeqlFolder;
logger.debug(`CodeQL found in cache ${codeqlFolder}`);
break;
case "download":
codeqlFolder = await downloadCodeQL(
source.codeqlURL,
source.semanticVersion,
apiDetails,
tempDir,
logger
);
break;
default:
util.assertNever(source);
} }
return { codeqlFolder, toolsVersion: source.toolsVersion };
return s;
} }