diff --git a/lib/entry-points.js b/lib/entry-points.js index 3052ae2013..03ee3761a1 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -19179,12 +19179,12 @@ var require_lib = __commonJS({ throw new Error("Client has already been disposed."); } const parsedUrl = new URL(requestUrl); - let info7 = this._prepareRequest(verb, parsedUrl, headers); + let info8 = this._prepareRequest(verb, parsedUrl, headers); const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) ? this._maxRetries + 1 : 1; let numTries = 0; let response; do { - response = yield this.requestRaw(info7, data); + response = yield this.requestRaw(info8, data); if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) { let authenticationHandler; for (const handler2 of this.handlers) { @@ -19194,7 +19194,7 @@ var require_lib = __commonJS({ } } if (authenticationHandler) { - return authenticationHandler.handleAuthentication(this, info7, data); + return authenticationHandler.handleAuthentication(this, info8, data); } else { return response; } @@ -19217,8 +19217,8 @@ var require_lib = __commonJS({ } } } - info7 = this._prepareRequest(verb, parsedRedirectUrl, headers); - response = yield this.requestRaw(info7, data); + info8 = this._prepareRequest(verb, parsedRedirectUrl, headers); + response = yield this.requestRaw(info8, data); redirectsRemaining--; } if (!response.message.statusCode || !HttpResponseRetryCodes.includes(response.message.statusCode)) { @@ -19247,7 +19247,7 @@ var require_lib = __commonJS({ * @param info * @param data */ - requestRaw(info7, data) { + requestRaw(info8, data) { return __awaiter2(this, void 0, void 0, function* () { return new Promise((resolve13, reject) => { function callbackForResult(err, res) { @@ -19259,7 +19259,7 @@ var require_lib = __commonJS({ resolve13(res); } } - this.requestRawWithCallback(info7, data, callbackForResult); + this.requestRawWithCallback(info8, data, callbackForResult); }); }); } @@ -19269,12 +19269,12 @@ var require_lib = __commonJS({ * @param data * @param onResult */ - requestRawWithCallback(info7, data, onResult) { + requestRawWithCallback(info8, data, onResult) { if (typeof data === "string") { - if (!info7.options.headers) { - info7.options.headers = {}; + if (!info8.options.headers) { + info8.options.headers = {}; } - info7.options.headers["Content-Length"] = Buffer.byteLength(data, "utf8"); + info8.options.headers["Content-Length"] = Buffer.byteLength(data, "utf8"); } let callbackCalled = false; function handleResult(err, res) { @@ -19283,7 +19283,7 @@ var require_lib = __commonJS({ onResult(err, res); } } - const req = info7.httpModule.request(info7.options, (msg) => { + const req = info8.httpModule.request(info8.options, (msg) => { const res = new HttpClientResponse(msg); handleResult(void 0, res); }); @@ -19295,7 +19295,7 @@ var require_lib = __commonJS({ if (socket) { socket.end(); } - handleResult(new Error(`Request timeout: ${info7.options.path}`)); + handleResult(new Error(`Request timeout: ${info8.options.path}`)); }); req.on("error", function(err) { handleResult(err); @@ -19331,27 +19331,27 @@ var require_lib = __commonJS({ return this._getProxyAgentDispatcher(parsedUrl, proxyUrl); } _prepareRequest(method, requestUrl, headers) { - const info7 = {}; - info7.parsedUrl = requestUrl; - const usingSsl = info7.parsedUrl.protocol === "https:"; - info7.httpModule = usingSsl ? https3 : http; + const info8 = {}; + info8.parsedUrl = requestUrl; + const usingSsl = info8.parsedUrl.protocol === "https:"; + info8.httpModule = usingSsl ? https3 : http; const defaultPort = usingSsl ? 443 : 80; - info7.options = {}; - info7.options.host = info7.parsedUrl.hostname; - info7.options.port = info7.parsedUrl.port ? parseInt(info7.parsedUrl.port) : defaultPort; - info7.options.path = (info7.parsedUrl.pathname || "") + (info7.parsedUrl.search || ""); - info7.options.method = method; - info7.options.headers = this._mergeHeaders(headers); + info8.options = {}; + info8.options.host = info8.parsedUrl.hostname; + info8.options.port = info8.parsedUrl.port ? parseInt(info8.parsedUrl.port) : defaultPort; + info8.options.path = (info8.parsedUrl.pathname || "") + (info8.parsedUrl.search || ""); + info8.options.method = method; + info8.options.headers = this._mergeHeaders(headers); if (this.userAgent != null) { - info7.options.headers["user-agent"] = this.userAgent; + info8.options.headers["user-agent"] = this.userAgent; } - info7.options.agent = this._getAgent(info7.parsedUrl); + info8.options.agent = this._getAgent(info8.parsedUrl); if (this.handlers) { for (const handler2 of this.handlers) { - handler2.prepareRequest(info7.options); + handler2.prepareRequest(info8.options); } } - return info7; + return info8; } _mergeHeaders(headers) { if (this.requestOptions && this.requestOptions.headers) { @@ -21406,7 +21406,7 @@ var require_core = __commonJS({ exports2.error = error3; exports2.warning = warning14; exports2.notice = notice; - exports2.info = info7; + exports2.info = info8; exports2.startGroup = startGroup4; exports2.endGroup = endGroup4; exports2.group = group; @@ -21503,7 +21503,7 @@ Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); function notice(message, properties = {}) { (0, command_1.issueCommand)("notice", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); } - function info7(message) { + function info8(message) { process.stdout.write(message + os7.EOL); } function startGroup4(name) { @@ -42402,12 +42402,12 @@ var require_operationHelpers = __commonJS({ if (hasOriginalRequest(request3)) { return getOperationRequestInfo(request3[originalRequestSymbol]); } - let info7 = state_js_1.state.operationRequestMap.get(request3); - if (!info7) { - info7 = {}; - state_js_1.state.operationRequestMap.set(request3, info7); + let info8 = state_js_1.state.operationRequestMap.get(request3); + if (!info8) { + info8 = {}; + state_js_1.state.operationRequestMap.set(request3, info8); } - return info7; + return info8; } } }); @@ -76954,9 +76954,9 @@ var require_reflection_type_check = __commonJS({ var reflection_info_1 = require_reflection_info(); var oneof_1 = require_oneof(); var ReflectionTypeCheck = class { - constructor(info7) { + constructor(info8) { var _a; - this.fields = (_a = info7.fields) !== null && _a !== void 0 ? _a : []; + this.fields = (_a = info8.fields) !== null && _a !== void 0 ? _a : []; } prepare() { if (this.data) @@ -77202,8 +77202,8 @@ var require_reflection_json_reader = __commonJS({ var assert_1 = require_assert(); var reflection_long_convert_1 = require_reflection_long_convert(); var ReflectionJsonReader = class { - constructor(info7) { - this.info = info7; + constructor(info8) { + this.info = info8; } prepare() { var _a; @@ -77499,9 +77499,9 @@ var require_reflection_json_writer = __commonJS({ var reflection_info_1 = require_reflection_info(); var assert_1 = require_assert(); var ReflectionJsonWriter = class { - constructor(info7) { + constructor(info8) { var _a; - this.fields = (_a = info7.fields) !== null && _a !== void 0 ? _a : []; + this.fields = (_a = info8.fields) !== null && _a !== void 0 ? _a : []; } /** * Converts the message to a JSON object, based on the field descriptors. @@ -77754,8 +77754,8 @@ var require_reflection_binary_reader = __commonJS({ var reflection_long_convert_1 = require_reflection_long_convert(); var reflection_scalar_default_1 = require_reflection_scalar_default(); var ReflectionBinaryReader = class { - constructor(info7) { - this.info = info7; + constructor(info8) { + this.info = info8; } prepare() { var _a; @@ -77928,8 +77928,8 @@ var require_reflection_binary_writer = __commonJS({ var assert_1 = require_assert(); var pb_long_1 = require_pb_long(); var ReflectionBinaryWriter = class { - constructor(info7) { - this.info = info7; + constructor(info8) { + this.info = info8; } prepare() { if (!this.fields) { @@ -78179,9 +78179,9 @@ var require_reflection_merge_partial = __commonJS({ "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.reflectionMergePartial = void 0; - function reflectionMergePartial(info7, target, source) { + function reflectionMergePartial(info8, target, source) { let fieldValue, input = source, output; - for (let field of info7.fields) { + for (let field of info8.fields) { let name = field.localName; if (field.oneof) { const group = input[field.oneof]; @@ -78250,12 +78250,12 @@ var require_reflection_equals = __commonJS({ Object.defineProperty(exports2, "__esModule", { value: true }); exports2.reflectionEquals = void 0; var reflection_info_1 = require_reflection_info(); - function reflectionEquals(info7, a, b) { + function reflectionEquals(info8, a, b) { if (a === b) return true; if (!a || !b) return false; - for (let field of info7.fields) { + for (let field of info8.fields) { let localName = field.localName; let val_a = field.oneof ? a[field.oneof][localName] : a[localName]; let val_b = field.oneof ? b[field.oneof][localName] : b[localName]; @@ -91275,7 +91275,7 @@ var require_async = __commonJS({ } } var sortBy$1 = awaitify(sortBy, 3); - function timeout(asyncFn, milliseconds, info7) { + function timeout(asyncFn, milliseconds, info8) { var fn = wrapAsync(asyncFn); return initialParams((args, callback) => { var timedOut = false; @@ -91284,8 +91284,8 @@ var require_async = __commonJS({ var name = asyncFn.name || "anonymous"; var error3 = new Error('Callback function "' + name + '" timed out.'); error3.code = "ETIMEDOUT"; - if (info7) { - error3.info = info7; + if (info8) { + error3.info = info8; } timedOut = true; callback(error3); @@ -114681,12 +114681,12 @@ var require_lib4 = __commonJS({ throw new Error("Client has already been disposed."); } const parsedUrl = new URL(requestUrl); - let info7 = this._prepareRequest(verb, parsedUrl, headers); + let info8 = this._prepareRequest(verb, parsedUrl, headers); const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) ? this._maxRetries + 1 : 1; let numTries = 0; let response; do { - response = yield this.requestRaw(info7, data); + response = yield this.requestRaw(info8, data); if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) { let authenticationHandler; for (const handler2 of this.handlers) { @@ -114696,7 +114696,7 @@ var require_lib4 = __commonJS({ } } if (authenticationHandler) { - return authenticationHandler.handleAuthentication(this, info7, data); + return authenticationHandler.handleAuthentication(this, info8, data); } else { return response; } @@ -114719,8 +114719,8 @@ var require_lib4 = __commonJS({ } } } - info7 = this._prepareRequest(verb, parsedRedirectUrl, headers); - response = yield this.requestRaw(info7, data); + info8 = this._prepareRequest(verb, parsedRedirectUrl, headers); + response = yield this.requestRaw(info8, data); redirectsRemaining--; } if (!response.message.statusCode || !HttpResponseRetryCodes.includes(response.message.statusCode)) { @@ -114749,7 +114749,7 @@ var require_lib4 = __commonJS({ * @param info * @param data */ - requestRaw(info7, data) { + requestRaw(info8, data) { return __awaiter2(this, void 0, void 0, function* () { return new Promise((resolve13, reject) => { function callbackForResult(err, res) { @@ -114761,7 +114761,7 @@ var require_lib4 = __commonJS({ resolve13(res); } } - this.requestRawWithCallback(info7, data, callbackForResult); + this.requestRawWithCallback(info8, data, callbackForResult); }); }); } @@ -114771,12 +114771,12 @@ var require_lib4 = __commonJS({ * @param data * @param onResult */ - requestRawWithCallback(info7, data, onResult) { + requestRawWithCallback(info8, data, onResult) { if (typeof data === "string") { - if (!info7.options.headers) { - info7.options.headers = {}; + if (!info8.options.headers) { + info8.options.headers = {}; } - info7.options.headers["Content-Length"] = Buffer.byteLength(data, "utf8"); + info8.options.headers["Content-Length"] = Buffer.byteLength(data, "utf8"); } let callbackCalled = false; function handleResult(err, res) { @@ -114785,7 +114785,7 @@ var require_lib4 = __commonJS({ onResult(err, res); } } - const req = info7.httpModule.request(info7.options, (msg) => { + const req = info8.httpModule.request(info8.options, (msg) => { const res = new HttpClientResponse(msg); handleResult(void 0, res); }); @@ -114797,7 +114797,7 @@ var require_lib4 = __commonJS({ if (socket) { socket.end(); } - handleResult(new Error(`Request timeout: ${info7.options.path}`)); + handleResult(new Error(`Request timeout: ${info8.options.path}`)); }); req.on("error", function(err) { handleResult(err); @@ -114833,27 +114833,27 @@ var require_lib4 = __commonJS({ return this._getProxyAgentDispatcher(parsedUrl, proxyUrl); } _prepareRequest(method, requestUrl, headers) { - const info7 = {}; - info7.parsedUrl = requestUrl; - const usingSsl = info7.parsedUrl.protocol === "https:"; - info7.httpModule = usingSsl ? https3 : http; + const info8 = {}; + info8.parsedUrl = requestUrl; + const usingSsl = info8.parsedUrl.protocol === "https:"; + info8.httpModule = usingSsl ? https3 : http; const defaultPort = usingSsl ? 443 : 80; - info7.options = {}; - info7.options.host = info7.parsedUrl.hostname; - info7.options.port = info7.parsedUrl.port ? parseInt(info7.parsedUrl.port) : defaultPort; - info7.options.path = (info7.parsedUrl.pathname || "") + (info7.parsedUrl.search || ""); - info7.options.method = method; - info7.options.headers = this._mergeHeaders(headers); + info8.options = {}; + info8.options.host = info8.parsedUrl.hostname; + info8.options.port = info8.parsedUrl.port ? parseInt(info8.parsedUrl.port) : defaultPort; + info8.options.path = (info8.parsedUrl.pathname || "") + (info8.parsedUrl.search || ""); + info8.options.method = method; + info8.options.headers = this._mergeHeaders(headers); if (this.userAgent != null) { - info7.options.headers["user-agent"] = this.userAgent; + info8.options.headers["user-agent"] = this.userAgent; } - info7.options.agent = this._getAgent(info7.parsedUrl); + info8.options.agent = this._getAgent(info8.parsedUrl); if (this.handlers) { for (const handler2 of this.handlers) { - handler2.prepareRequest(info7.options); + handler2.prepareRequest(info8.options); } } - return info7; + return info8; } _mergeHeaders(headers) { if (this.requestOptions && this.requestOptions.headers) { @@ -121241,11 +121241,11 @@ var require_dist_node12 = __commonJS({ } async function wrapRequest2(state, request3, options) { const limiter = new Bottleneck2(); - limiter.on("failed", function(error3, info7) { + limiter.on("failed", function(error3, info8) { const maxRetries = ~~error3.request.request.retries; const after = ~~error3.request.request.retryAfter; - options.request.retryCount = info7.retryCount + 1; - if (maxRetries > info7.retryCount) { + options.request.retryCount = info8.retryCount + 1; + if (maxRetries > info8.retryCount) { return after * state.retryAfterBaseValue; } }); @@ -122453,12 +122453,12 @@ var require_lib5 = __commonJS({ throw new Error("Client has already been disposed."); } const parsedUrl = new URL(requestUrl); - let info7 = this._prepareRequest(verb, parsedUrl, headers); + let info8 = this._prepareRequest(verb, parsedUrl, headers); const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) ? this._maxRetries + 1 : 1; let numTries = 0; let response; do { - response = yield this.requestRaw(info7, data); + response = yield this.requestRaw(info8, data); if (response && response.message && response.message.statusCode === HttpCodes.Unauthorized) { let authenticationHandler; for (const handler2 of this.handlers) { @@ -122468,7 +122468,7 @@ var require_lib5 = __commonJS({ } } if (authenticationHandler) { - return authenticationHandler.handleAuthentication(this, info7, data); + return authenticationHandler.handleAuthentication(this, info8, data); } else { return response; } @@ -122491,8 +122491,8 @@ var require_lib5 = __commonJS({ } } } - info7 = this._prepareRequest(verb, parsedRedirectUrl, headers); - response = yield this.requestRaw(info7, data); + info8 = this._prepareRequest(verb, parsedRedirectUrl, headers); + response = yield this.requestRaw(info8, data); redirectsRemaining--; } if (!response.message.statusCode || !HttpResponseRetryCodes.includes(response.message.statusCode)) { @@ -122521,7 +122521,7 @@ var require_lib5 = __commonJS({ * @param info * @param data */ - requestRaw(info7, data) { + requestRaw(info8, data) { return __awaiter2(this, void 0, void 0, function* () { return new Promise((resolve13, reject) => { function callbackForResult(err, res) { @@ -122533,7 +122533,7 @@ var require_lib5 = __commonJS({ resolve13(res); } } - this.requestRawWithCallback(info7, data, callbackForResult); + this.requestRawWithCallback(info8, data, callbackForResult); }); }); } @@ -122543,12 +122543,12 @@ var require_lib5 = __commonJS({ * @param data * @param onResult */ - requestRawWithCallback(info7, data, onResult) { + requestRawWithCallback(info8, data, onResult) { if (typeof data === "string") { - if (!info7.options.headers) { - info7.options.headers = {}; + if (!info8.options.headers) { + info8.options.headers = {}; } - info7.options.headers["Content-Length"] = Buffer.byteLength(data, "utf8"); + info8.options.headers["Content-Length"] = Buffer.byteLength(data, "utf8"); } let callbackCalled = false; function handleResult(err, res) { @@ -122557,7 +122557,7 @@ var require_lib5 = __commonJS({ onResult(err, res); } } - const req = info7.httpModule.request(info7.options, (msg) => { + const req = info8.httpModule.request(info8.options, (msg) => { const res = new HttpClientResponse(msg); handleResult(void 0, res); }); @@ -122569,7 +122569,7 @@ var require_lib5 = __commonJS({ if (socket) { socket.end(); } - handleResult(new Error(`Request timeout: ${info7.options.path}`)); + handleResult(new Error(`Request timeout: ${info8.options.path}`)); }); req.on("error", function(err) { handleResult(err); @@ -122605,27 +122605,27 @@ var require_lib5 = __commonJS({ return this._getProxyAgentDispatcher(parsedUrl, proxyUrl); } _prepareRequest(method, requestUrl, headers) { - const info7 = {}; - info7.parsedUrl = requestUrl; - const usingSsl = info7.parsedUrl.protocol === "https:"; - info7.httpModule = usingSsl ? https3 : http; + const info8 = {}; + info8.parsedUrl = requestUrl; + const usingSsl = info8.parsedUrl.protocol === "https:"; + info8.httpModule = usingSsl ? https3 : http; const defaultPort = usingSsl ? 443 : 80; - info7.options = {}; - info7.options.host = info7.parsedUrl.hostname; - info7.options.port = info7.parsedUrl.port ? parseInt(info7.parsedUrl.port) : defaultPort; - info7.options.path = (info7.parsedUrl.pathname || "") + (info7.parsedUrl.search || ""); - info7.options.method = method; - info7.options.headers = this._mergeHeaders(headers); + info8.options = {}; + info8.options.host = info8.parsedUrl.hostname; + info8.options.port = info8.parsedUrl.port ? parseInt(info8.parsedUrl.port) : defaultPort; + info8.options.path = (info8.parsedUrl.pathname || "") + (info8.parsedUrl.search || ""); + info8.options.method = method; + info8.options.headers = this._mergeHeaders(headers); if (this.userAgent != null) { - info7.options.headers["user-agent"] = this.userAgent; + info8.options.headers["user-agent"] = this.userAgent; } - info7.options.agent = this._getAgent(info7.parsedUrl); + info8.options.agent = this._getAgent(info8.parsedUrl); if (this.handlers) { for (const handler2 of this.handlers) { - handler2.prepareRequest(info7.options); + handler2.prepareRequest(info8.options); } } - return info7; + return info8; } _mergeHeaders(headers) { if (this.requestOptions && this.requestOptions.headers) { @@ -124615,10 +124615,10 @@ Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); (0, command_1.issueCommand)("notice", (0, utils_1.toCommandProperties)(properties), message instanceof Error ? message.toString() : message); } exports2.notice = notice; - function info7(message) { + function info8(message) { process.stdout.write(message + os7.EOL); } - exports2.info = info7; + exports2.info = info8; function startGroup4(name) { (0, command_1.issue)("group", name); } @@ -148062,14 +148062,34 @@ function asHTTPError(arg) { return void 0; } var cachedCodeQlVersion = void 0; -function cacheCodeQlVersion(version) { +function cacheCodeQlVersion(cmd, version) { if (cachedCodeQlVersion !== void 0) { throw new Error("cacheCodeQlVersion() should be called only once"); } cachedCodeQlVersion = version; + core3.exportVariable( + "CODEQL_ACTION_CLI_VERSION_INFO" /* CODEQL_VERSION_INFO */, + JSON.stringify({ cmd, version }) + ); } -function getCachedCodeQlVersion() { - return cachedCodeQlVersion; +function getCachedCodeQlVersion(cmd) { + if (cachedCodeQlVersion !== void 0) { + return cachedCodeQlVersion; + } + const serialized = process.env["CODEQL_ACTION_CLI_VERSION_INFO" /* CODEQL_VERSION_INFO */]; + if (!serialized) { + return void 0; + } + let persisted; + try { + persisted = JSON.parse(serialized); + } catch { + return void 0; + } + if (typeof persisted?.version?.version !== "string" || cmd !== void 0 && persisted.cmd !== cmd) { + return void 0; + } + return persisted.version; } async function codeQlVersionAtLeast(codeql, requiredVersion) { return semver.gte((await codeql.getVersion()).version, requiredVersion); @@ -148669,11 +148689,11 @@ async function errorRequest(state, octokit, error3, options) { } async function wrapRequest(state, octokit, request3, options) { const limiter = new import_light.default(); - limiter.on("failed", function(error3, info7) { + limiter.on("failed", function(error3, info8) { const maxRetries = ~~error3.request.request?.retries; const after = ~~error3.request.request?.retryAfter; - options.request.retryCount = info7.retryCount + 1; - if (maxRetries > info7.retryCount) { + options.request.retryCount = info8.retryCount + 1; + if (maxRetries > info8.retryCount) { return after * state.retryAfterBaseValue; } }); @@ -153873,7 +153893,7 @@ async function getCodeQLForCmd(cmd, checkVersion) { return cmd; }, async getVersion() { - let result = getCachedCodeQlVersion(); + let result = getCachedCodeQlVersion(cmd); if (result === void 0) { const output = await runCli(cmd, ["version", "--format=json"], { noStreamStdout: true @@ -153885,12 +153905,12 @@ async function getCodeQLForCmd(cmd, checkVersion) { `Invalid JSON output from \`version --format=json\`: ${output}` ); } - cacheCodeQlVersion(result); + cacheCodeQlVersion(cmd, result); } return result; }, async printVersion() { - await runCli(cmd, ["version", "--format=json"]); + core11.info(JSON.stringify(await this.getVersion(), null, 2)); }, async supportsFeature(feature) { return isSupportedToolsFeature(await this.getVersion(), feature); diff --git a/src/codeql.ts b/src/codeql.ts index 19f933c39a..afae491a4a 100644 --- a/src/codeql.ts +++ b/src/codeql.ts @@ -523,7 +523,7 @@ async function getCodeQLForCmd( return cmd; }, async getVersion() { - let result = util.getCachedCodeQlVersion(); + let result = util.getCachedCodeQlVersion(cmd); if (result === undefined) { const output = await runCli(cmd, ["version", "--format=json"], { noStreamStdout: true, @@ -535,12 +535,13 @@ async function getCodeQLForCmd( `Invalid JSON output from \`version --format=json\`: ${output}`, ); } - util.cacheCodeQlVersion(result); + util.cacheCodeQlVersion(cmd, result); } return result; }, async printVersion() { - await runCli(cmd, ["version", "--format=json"]); + // Reuse the cached version information rather than invoking the CLI again. + core.info(JSON.stringify(await this.getVersion(), null, 2)); }, async supportsFeature(feature: ToolsFeature) { return isSupportedToolsFeature(await this.getVersion(), feature); diff --git a/src/environment.ts b/src/environment.ts index ed44ddcff2..c3f54ebd27 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -17,6 +17,12 @@ export enum EnvVar { */ CLI_VERBOSITY = "CODEQL_VERBOSITY", + /** + * `PersistedVersionInfo` for the CodeQL CLI, so later Actions steps can reuse it instead of + * invoking `codeql version` again. + */ + CODEQL_VERSION_INFO = "CODEQL_ACTION_CLI_VERSION_INFO", + /** Whether the CodeQL Action has invoked the Go autobuilder. */ DID_AUTOBUILD_GOLANG = "CODEQL_ACTION_DID_AUTOBUILD_GOLANG", diff --git a/src/util.test.ts b/src/util.test.ts index cca457cbe6..8760b77e21 100644 --- a/src/util.test.ts +++ b/src/util.test.ts @@ -532,3 +532,26 @@ test("Failure.orElse returns the default value for a failure result", (t) => { const result = new util.Failure(new Error("test error")); t.is(result.orElse("default value"), "default value"); }); + +test("getCachedCodeQlVersion reuses a version persisted by an earlier step", (t) => { + process.env[EnvVar.CODEQL_VERSION_INFO] = JSON.stringify({ + cmd: "/path/to/codeql", + version: { version: "2.20.0" }, + }); + t.deepEqual(util.getCachedCodeQlVersion("/path/to/codeql"), { + version: "2.20.0", + }); +}); + +test("getCachedCodeQlVersion ignores a persisted version from a different CLI", (t) => { + process.env[EnvVar.CODEQL_VERSION_INFO] = JSON.stringify({ + cmd: "/path/to/other-codeql", + version: { version: "2.20.0" }, + }); + t.is(util.getCachedCodeQlVersion("/path/to/codeql"), undefined); +}); + +test("getCachedCodeQlVersion ignores a malformed persisted value", (t) => { + process.env[EnvVar.CODEQL_VERSION_INFO] = "not valid json"; + t.is(util.getCachedCodeQlVersion("/path/to/codeql"), undefined); +}); diff --git a/src/util.ts b/src/util.ts index e2331461bd..c9a20b467d 100644 --- a/src/util.ts +++ b/src/util.ts @@ -619,15 +619,51 @@ export function asHTTPError(arg: any): HTTPError | undefined { let cachedCodeQlVersion: undefined | VersionInfo = undefined; -export function cacheCodeQlVersion(version: VersionInfo): void { +/** The persisted version together with the CLI path it was obtained from. */ +interface PersistedVersionInfo { + cmd: string; + version: VersionInfo; +} + +export function cacheCodeQlVersion(cmd: string, version: VersionInfo): void { if (cachedCodeQlVersion !== undefined) { throw new Error("cacheCodeQlVersion() should be called only once"); } cachedCodeQlVersion = version; + // Persist the version so that subsequent Actions steps, which run in separate + // processes, can reuse it rather than invoking `codeql version` again. We + // record the CLI path so that a different step using a different CodeQL bundle + // doesn't pick up a stale version. + core.exportVariable( + EnvVar.CODEQL_VERSION_INFO, + JSON.stringify({ cmd, version }), + ); } -export function getCachedCodeQlVersion(): undefined | VersionInfo { - return cachedCodeQlVersion; +export function getCachedCodeQlVersion(cmd?: string): undefined | VersionInfo { + if (cachedCodeQlVersion !== undefined) { + return cachedCodeQlVersion; + } + // Fall back to the value persisted by an earlier Actions step, if any. This is + // best-effort: any malformed or mismatched value is ignored so that the caller + // invokes `codeql version` instead. + const serialized = process.env[EnvVar.CODEQL_VERSION_INFO]; + if (!serialized) { + return undefined; + } + let persisted: PersistedVersionInfo; + try { + persisted = JSON.parse(serialized) as PersistedVersionInfo; + } catch { + return undefined; + } + if ( + typeof persisted?.version?.version !== "string" || + (cmd !== undefined && persisted.cmd !== cmd) + ) { + return undefined; + } + return persisted.version; } export async function codeQlVersionAtLeast(