diff --git a/lib/entry-points.js b/lib/entry-points.js index b2bb9c1835..b9fe4c33b8 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -42430,7 +42430,7 @@ var require_cacheUtils = __commonJS({ var crypto3 = __importStar2(require("crypto")); var fs34 = __importStar2(require("fs")); var path30 = __importStar2(require("path")); - var semver12 = __importStar2(require_semver3()); + var semver13 = __importStar2(require_semver3()); var util4 = __importStar2(require("util")); var constants_1 = require_constants7(); var versionSalt = "1.0"; @@ -42523,7 +42523,7 @@ var require_cacheUtils = __commonJS({ function getCompressionMethod() { return __awaiter2(this, void 0, void 0, function* () { const versionOutput = yield getVersion("zstd", ["--quiet"]); - const version = semver12.clean(versionOutput); + const version = semver13.clean(versionOutput); core29.debug(`zstd version: ${version}`); if (versionOutput === "") { return constants_1.CompressionMethod.Gzip; @@ -50678,11 +50678,11 @@ var require_tracingPolicy = __commonJS({ var import_log = require_log3(); var import_core_util = require_commonjs4(); var import_restError = require_restError3(); - var import_util62 = require_internal3(); + var import_util61 = require_internal3(); var tracingPolicyName2 = "tracingPolicy"; function tracingPolicy2(options = {}) { const userAgentPromise = (0, import_userAgent.getUserAgentValue)(options.userAgentPrefix); - const sanitizer = new import_util62.Sanitizer({ + const sanitizer = new import_util61.Sanitizer({ additionalAllowedQueryParameters: options.additionalAllowedQueryParameters }); const tracingClient = tryCreateTracingClient(); @@ -54308,11 +54308,11 @@ var require_response2 = __commonJS({ }); module2.exports = __toCommonJS2(response_exports); var import_core_rest_pipeline = require_commonjs6(); - var import_util62 = require_util7(); + var import_util61 = require_util7(); var originalResponse = /* @__PURE__ */ Symbol("Original FullOperationResponse"); function toCompatResponse2(response, options) { - let request3 = (0, import_util62.toWebResourceLike)(response.request); - let headers = (0, import_util62.toHttpHeadersLike)(response.headers); + let request3 = (0, import_util61.toWebResourceLike)(response.request); + let headers = (0, import_util61.toHttpHeadersLike)(response.headers); if (options?.createProxy) { return new Proxy(response, { get(target, prop, receiver) { @@ -54353,7 +54353,7 @@ var require_response2 = __commonJS({ return { ...compatResponse, headers, - request: (0, import_util62.toPipelineRequest)(compatResponse.request) + request: (0, import_util61.toPipelineRequest)(compatResponse.request) }; } } @@ -54460,7 +54460,7 @@ var require_requestPolicyFactoryPolicy = __commonJS({ requestPolicyFactoryPolicyName: () => requestPolicyFactoryPolicyName2 }); module2.exports = __toCommonJS2(requestPolicyFactoryPolicy_exports); - var import_util62 = require_util7(); + var import_util61 = require_util7(); var import_response = require_response2(); var HttpPipelineLogLevel2 = /* @__PURE__ */ ((HttpPipelineLogLevel22) => { HttpPipelineLogLevel22[HttpPipelineLogLevel22["ERROR"] = 1] = "ERROR"; @@ -54484,14 +54484,14 @@ var require_requestPolicyFactoryPolicy = __commonJS({ async sendRequest(request3, next) { let httpPipeline = { async sendRequest(httpRequest) { - const response2 = await next((0, import_util62.toPipelineRequest)(httpRequest)); + const response2 = await next((0, import_util61.toPipelineRequest)(httpRequest)); return (0, import_response.toCompatResponse)(response2, { createProxy: true }); } }; for (const factory of orderedFactories) { httpPipeline = factory.create(httpPipeline, mockRequestPolicyOptions); } - const webResourceLike = (0, import_util62.toWebResourceLike)(request3, { createProxy: true }); + const webResourceLike = (0, import_util61.toWebResourceLike)(request3, { createProxy: true }); const response = await httpPipeline.sendRequest(webResourceLike); return (0, import_response.toPipelineResponse)(response); } @@ -54526,12 +54526,12 @@ var require_httpClientAdapter = __commonJS({ }); module2.exports = __toCommonJS2(httpClientAdapter_exports); var import_response = require_response2(); - var import_util62 = require_util7(); + var import_util61 = require_util7(); function convertHttpClient2(requestPolicyClient) { return { sendRequest: async (request3) => { const response = await requestPolicyClient.sendRequest( - (0, import_util62.toWebResourceLike)(request3, { createProxy: true }) + (0, import_util61.toWebResourceLike)(request3, { createProxy: true }) ); return (0, import_response.toPipelineResponse)(response); } @@ -54569,7 +54569,7 @@ var require_commonjs9 = __commonJS({ disableKeepAlivePolicyName: () => import_disableKeepAlivePolicy.disableKeepAlivePolicyName, requestPolicyFactoryPolicyName: () => import_requestPolicyFactoryPolicy.requestPolicyFactoryPolicyName, toCompatResponse: () => import_response.toCompatResponse, - toHttpHeadersLike: () => import_util62.toHttpHeadersLike + toHttpHeadersLike: () => import_util61.toHttpHeadersLike }); module2.exports = __toCommonJS2(src_exports); var import_extendedClient = require_extendedClient(); @@ -54577,7 +54577,7 @@ var require_commonjs9 = __commonJS({ var import_requestPolicyFactoryPolicy = require_requestPolicyFactoryPolicy(); var import_disableKeepAlivePolicy = require_disableKeepAlivePolicy(); var import_httpClientAdapter = require_httpClientAdapter(); - var import_util62 = require_util7(); + var import_util61 = require_util7(); } }); @@ -114072,7 +114072,7 @@ var require_manifest = __commonJS({ exports2._findMatch = _findMatch; exports2._getOsVersion = _getOsVersion; exports2._readLinuxVersionFile = _readLinuxVersionFile; - var semver12 = __importStar2(require_semver2()); + var semver13 = __importStar2(require_semver2()); var core_1 = require_core(); var os8 = require("os"); var cp = require("child_process"); @@ -114086,7 +114086,7 @@ var require_manifest = __commonJS({ for (const candidate of candidates) { const version = candidate.version; (0, core_1.debug)(`check ${version} satisfies ${versionSpec}`); - if (semver12.satisfies(version, versionSpec) && (!stable || candidate.stable === stable)) { + if (semver13.satisfies(version, versionSpec) && (!stable || candidate.stable === stable)) { file = candidate.files.find((item) => { (0, core_1.debug)(`${item.arch}===${archFilter} && ${item.platform}===${platFilter}`); let chk = item.arch === archFilter && item.platform === platFilter; @@ -114095,7 +114095,7 @@ var require_manifest = __commonJS({ if (osVersion === item.platform_version) { chk = true; } else { - chk = semver12.satisfies(osVersion, item.platform_version); + chk = semver13.satisfies(osVersion, item.platform_version); } } return chk; @@ -114355,7 +114355,7 @@ var require_tool_cache = __commonJS({ var os8 = __importStar2(require("os")); var path30 = __importStar2(require("path")); var httpm = __importStar2(require_lib()); - var semver12 = __importStar2(require_semver2()); + var semver13 = __importStar2(require_semver2()); var stream2 = __importStar2(require("stream")); var util4 = __importStar2(require("util")); var assert_1 = require("assert"); @@ -114628,7 +114628,7 @@ var require_tool_cache = __commonJS({ } function cacheDir2(sourceDir, tool, version, arch2) { return __awaiter2(this, void 0, void 0, function* () { - version = semver12.clean(version) || version; + version = semver13.clean(version) || version; arch2 = arch2 || os8.arch(); core29.debug(`Caching tool ${tool} ${version} ${arch2}`); core29.debug(`source dir: ${sourceDir}`); @@ -114646,7 +114646,7 @@ var require_tool_cache = __commonJS({ } function cacheFile(sourceFile, targetFile, tool, version, arch2) { return __awaiter2(this, void 0, void 0, function* () { - version = semver12.clean(version) || version; + version = semver13.clean(version) || version; arch2 = arch2 || os8.arch(); core29.debug(`Caching tool ${tool} ${version} ${arch2}`); core29.debug(`source file: ${sourceFile}`); @@ -114676,7 +114676,7 @@ var require_tool_cache = __commonJS({ } let toolPath = ""; if (versionSpec) { - versionSpec = semver12.clean(versionSpec) || ""; + versionSpec = semver13.clean(versionSpec) || ""; const cachePath = path30.join(_getCacheDirectory(), toolName, versionSpec, arch2); core29.debug(`checking cache: ${cachePath}`); if (fs34.existsSync(cachePath) && fs34.existsSync(`${cachePath}.complete`)) { @@ -114756,7 +114756,7 @@ var require_tool_cache = __commonJS({ } function _createToolPath(tool, version, arch2) { return __awaiter2(this, void 0, void 0, function* () { - const folderPath = path30.join(_getCacheDirectory(), tool, semver12.clean(version) || version, arch2 || ""); + const folderPath = path30.join(_getCacheDirectory(), tool, semver13.clean(version) || version, arch2 || ""); core29.debug(`destination ${folderPath}`); const markerPath = `${folderPath}.complete`; yield io9.rmRF(folderPath); @@ -114766,15 +114766,15 @@ var require_tool_cache = __commonJS({ }); } function _completeToolPath(tool, version, arch2) { - const folderPath = path30.join(_getCacheDirectory(), tool, semver12.clean(version) || version, arch2 || ""); + const folderPath = path30.join(_getCacheDirectory(), tool, semver13.clean(version) || version, arch2 || ""); const markerPath = `${folderPath}.complete`; fs34.writeFileSync(markerPath, ""); core29.debug("finished caching tool"); } function isExplicitVersion(versionSpec) { - const c = semver12.clean(versionSpec) || ""; + const c = semver13.clean(versionSpec) || ""; core29.debug(`isExplicit: ${c}`); - const valid4 = semver12.valid(c) != null; + const valid4 = semver13.valid(c) != null; core29.debug(`explicit? ${valid4}`); return valid4; } @@ -114782,14 +114782,14 @@ var require_tool_cache = __commonJS({ let version = ""; core29.debug(`evaluating ${versions.length} versions`); versions = versions.sort((a, b) => { - if (semver12.gt(a, b)) { + if (semver13.gt(a, b)) { return 1; } return -1; }); for (let i = versions.length - 1; i >= 0; i--) { const potential = versions[i]; - const satisfied = semver12.satisfies(potential, versionSpec); + const satisfied = semver13.satisfies(potential, versionSpec); if (satisfied) { version = potential; break; @@ -173905,6 +173905,17 @@ var Env = class extends ReadOnlyEnv { core.exportVariable(name, val); } } + /** + * Set some initial environment variables that we can set even without + * knowing what version of CodeQL we're running. + */ + initialise(version) { + this.export("CODEQL_ACTION_FEATURE_MULTI_LANGUAGE" /* FEATURE_MULTI_LANGUAGE */, "false"); + this.export("CODEQL_ACTION_FEATURE_SANDWICH" /* FEATURE_SANDWICH */, "false"); + this.export("CODEQL_ACTION_FEATURE_SARIF_COMBINE" /* FEATURE_SARIF_COMBINE */, "true"); + this.export("CODEQL_ACTION_FEATURE_WILL_UPLOAD" /* FEATURE_WILL_UPLOAD */, "true"); + this.export("CODEQL_ACTION_VERSION" /* VERSION */, version); + } /** Gets a value indicating whether `set` was called at least once. */ hasChanged() { return this.changed; @@ -177334,6 +177345,85 @@ function checkSchema(schema, obj, options = {}, path30 = "") { return result; } +// src/errors/index.ts +function wrapError(error3) { + return error3 instanceof Error ? error3 : new Error(String(error3)); +} +function getErrorMessage(error3) { + return error3 instanceof Error ? error3.message : String(error3); +} +function isErrnoException(error3) { + return typeof error3 === "object" && error3 !== null && "code" in error3 && typeof error3.code === "string"; +} +function isDiskConfigurationError(e) { + if (!(e instanceof Error)) { + return false; + } + return ( + // out of disk space + e.message.includes("ENOSPC") || // access denied + e.message.includes("EACCES") + ); +} +var ConfigurationError = class extends Error { +}; +var HTTPError = class extends Error { + status; + constructor(message, status) { + super(message); + this.status = status; + } +}; +function asHTTPError(arg) { + if (!isObject2(arg) || !isString(arg.message)) { + return void 0; + } + if (Number.isInteger(arg.status)) { + return new HTTPError(arg.message, arg.status); + } + if (Number.isInteger(arg.httpStatusCode)) { + return new HTTPError(arg.message, arg.httpStatusCode); + } + return void 0; +} + +// src/github.ts +var GITHUB_DOTCOM_URL = "https://github.com"; +function parseGitHubUrl(inputUrl) { + const originalUrl = inputUrl; + if (inputUrl.indexOf("://") === -1) { + inputUrl = `https://${inputUrl}`; + } + if (!inputUrl.startsWith("http://") && !inputUrl.startsWith("https://")) { + throw new ConfigurationError(`"${originalUrl}" is not a http or https URL`); + } + let url2; + try { + url2 = new URL(inputUrl); + } catch { + throw new ConfigurationError(`"${originalUrl}" is not a valid URL`); + } + if (url2.hostname === "github.com" || url2.hostname === "api.github.com") { + return GITHUB_DOTCOM_URL; + } + if (url2.pathname.indexOf("/api/v3") !== -1) { + url2.pathname = url2.pathname.substring(0, url2.pathname.indexOf("/api/v3")); + } + if (url2.hostname.startsWith("api.")) { + url2.hostname = url2.hostname.substring(4); + } + if (!url2.pathname.endsWith("/")) { + url2.pathname = `${url2.pathname}/`; + } + return url2.toString(); +} +function getCurrentInstance(env) { + return { + url: env.getRequired("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */), + apiURL: env.getRequired("GITHUB_API_URL" /* GITHUB_API_URL */) + }; +} + // src/util.ts var BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json"; var BROKEN_VERSIONS = ["0.0.0-20211207"]; @@ -177595,37 +177685,6 @@ var ExhaustivityCheckingError = class extends Error { function assertNever(value) { throw new ExhaustivityCheckingError(value); } -function initializeEnvironment(version, env = getEnv()) { - env.export("CODEQL_ACTION_FEATURE_MULTI_LANGUAGE" /* FEATURE_MULTI_LANGUAGE */, "false"); - env.export("CODEQL_ACTION_FEATURE_SANDWICH" /* FEATURE_SANDWICH */, "false"); - env.export("CODEQL_ACTION_FEATURE_SARIF_COMBINE" /* FEATURE_SARIF_COMBINE */, "true"); - env.export("CODEQL_ACTION_FEATURE_WILL_UPLOAD" /* FEATURE_WILL_UPLOAD */, "true"); - env.export("CODEQL_ACTION_VERSION" /* VERSION */, version); -} -var HTTPError = class extends Error { - status; - constructor(message, status) { - super(message); - this.status = status; - } -}; -var ConfigurationError = class extends Error { -}; -function asHTTPError(arg) { - if (!isObject2(arg) || !isString(arg.message)) { - return void 0; - } - if (Number.isInteger(arg.status)) { - return new HTTPError(arg.message, arg.status); - } - if (Number.isInteger(arg.httpStatusCode)) { - return new HTTPError(arg.message, arg.httpStatusCode); - } - return void 0; -} -async function codeQlVersionAtLeast(codeql, requiredVersion) { - return semver.gte((await codeql.getVersion()).version, requiredVersion); -} function getBaseDatabaseOidsFilePath(config) { return path.join(config.dbLocation, BASE_DATABASE_OIDS_FILE_NAME); } @@ -177767,15 +177826,6 @@ function parseMatrixInput(matrixInput) { ); } } -function wrapError(error3) { - return error3 instanceof Error ? error3 : new Error(String(error3)); -} -function getErrorMessage(error3) { - return error3 instanceof Error ? error3.message : String(error3); -} -function isErrnoException(error3) { - return typeof error3 === "object" && error3 !== null && "code" in error3 && typeof error3.code === "string"; -} function prettyPrintPack(pack) { return `${pack.name}${pack.version ? `@${pack.version}` : ""}${pack.path ? `:${pack.path}` : ""}`; } @@ -178432,43 +178482,6 @@ retry.VERSION = VERSION7; // src/api-client.ts var import_undici = __toESM(require_undici()); -// src/github.ts -var GITHUB_DOTCOM_URL = "https://github.com"; -function parseGitHubUrl(inputUrl) { - const originalUrl = inputUrl; - if (inputUrl.indexOf("://") === -1) { - inputUrl = `https://${inputUrl}`; - } - if (!inputUrl.startsWith("http://") && !inputUrl.startsWith("https://")) { - throw new ConfigurationError(`"${originalUrl}" is not a http or https URL`); - } - let url2; - try { - url2 = new URL(inputUrl); - } catch { - throw new ConfigurationError(`"${originalUrl}" is not a valid URL`); - } - if (url2.hostname === "github.com" || url2.hostname === "api.github.com") { - return GITHUB_DOTCOM_URL; - } - if (url2.pathname.indexOf("/api/v3") !== -1) { - url2.pathname = url2.pathname.substring(0, url2.pathname.indexOf("/api/v3")); - } - if (url2.hostname.startsWith("api.")) { - url2.hostname = url2.hostname.substring(4); - } - if (!url2.pathname.endsWith("/")) { - url2.pathname = `${url2.pathname}/`; - } - return url2.toString(); -} -function getCurrentInstance(env) { - return { - url: env.getRequired("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */), - apiURL: env.getRequired("GITHUB_API_URL" /* GITHUB_API_URL */) - }; -} - // src/repository.ts function isRepositoryNwoStr(val) { return val.includes("/"); @@ -180030,7 +180043,7 @@ var OfflineFeatures = class { } const minimumVersion2 = config.minimumVersion; if (codeql && minimumVersion2) { - if (!await codeQlVersionAtLeast(codeql, minimumVersion2)) { + if (!await codeql.isVersionAtLeast(minimumVersion2)) { this.logger.debug( `Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum version ${minimumVersion2}.` ); @@ -180453,6 +180466,7 @@ var fs18 = __toESM(require("fs")); var path15 = __toESM(require("path")); var core12 = __toESM(require_core()); var toolrunner3 = __toESM(require_toolrunner()); +var semver11 = __toESM(require_semver2()); // src/cli-errors.ts var SUPPORTED_PLATFORMS = [ @@ -182447,10 +182461,7 @@ function runnerHasSufficientDiskSpace(diskUsage, logger2, minimumDiskSpaceMb) { return true; } async function runnerHasSufficientMemory(codeql, ramInput, logger2) { - if (await codeQlVersionAtLeast( - codeql, - CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE - )) { + if (await codeql.isVersionAtLeast(CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE)) { logger2.debug( `Skipping memory check for overlay analysis because CodeQL version is at least ${CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE}.` ); @@ -182588,7 +182599,7 @@ async function validateOverlayDatabaseMode(overlayDatabaseMode, useOverlayDataba ); return new Failure("incompatible-build-mode" /* IncompatibleBuildMode */); } - if (!await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION)) { + if (!await codeql.isVersionAtLeast(CODEQL_OVERLAY_MINIMUM_VERSION)) { logger2.warning( `Cannot build an ${overlayDatabaseMode} database because the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. Falling back to creating a normal full database instead.` ); @@ -184787,16 +184798,6 @@ var CODEQL_NEXT_MINIMUM_VERSION = "2.22.4"; var GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.18"; var GHES_MOST_RECENT_DEPRECATION_DATE = "2026-10-16"; var EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++"; -function isDiskConfigurationError(e) { - if (!(e instanceof Error)) { - return false; - } - return ( - // out of disk space - e.message.includes("ENOSPC") || // access denied - e.message.includes("EACCES") - ); -} async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, rawLanguages, otherLanguagePacksReason, useOverlayAwareDefaultCliVersion, features, logger2, checkVersion) { try { const { @@ -184872,6 +184873,9 @@ async function getCodeQLForCmd(logger2, cmd, checkVersion, env = getEnv()) { } return result; }, + async isVersionAtLeast(requiredVersion) { + return semver11.gte((await this.getVersion()).version, requiredVersion); + }, async printVersion() { core12.info(JSON.stringify(await this.getVersion(), null, 2)); }, @@ -185286,11 +185290,11 @@ Output was: ${extractorPath}` await runCli(env, cmd, args); } }; - if (checkVersion && !await codeQlVersionAtLeast(codeql, CODEQL_MINIMUM_VERSION)) { + if (checkVersion && !await codeql.isVersionAtLeast(CODEQL_MINIMUM_VERSION)) { throw new ConfigurationError( `Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${(await codeql.getVersion()).version}` ); - } else if (checkVersion && env.getOptional("CODEQL_ACTION_SUPPRESS_DEPRECATED_SOON_WARNING" /* SUPPRESS_DEPRECATED_SOON_WARNING */) !== "true" && !await codeQlVersionAtLeast(codeql, CODEQL_NEXT_MINIMUM_VERSION)) { + } else if (checkVersion && env.getOptional("CODEQL_ACTION_SUPPRESS_DEPRECATED_SOON_WARNING" /* SUPPRESS_DEPRECATED_SOON_WARNING */) !== "true" && !await codeql.isVersionAtLeast(CODEQL_NEXT_MINIMUM_VERSION)) { const result = await codeql.getVersion(); core12.warning( `CodeQL CLI version ${result.version} was discontinued on ${GHES_MOST_RECENT_DEPRECATION_DATE} alongside GitHub Enterprise Server ${GHES_VERSION_MOST_RECENTLY_DEPRECATED} and will not be supported by the next minor release of the CodeQL Action. Please update to CodeQL CLI version ${CODEQL_NEXT_MINIMUM_VERSION} or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version. @@ -188585,7 +188589,7 @@ async function run(action) { let dependencyCacheResults; let databaseUploadResults = []; try { - initializeEnvironment(getActionVersion()); + action.env.initialise(getActionVersion()); persistInputs(); const statusReportBase = await createStatusReportBase( "finish" /* Analyze */, @@ -190911,7 +190915,7 @@ var import_async = __toESM(require_async(), 1); var import_path7 = require("path"); // node_modules/archiver/lib/error.js -var import_util38 = __toESM(require("util"), 1); +var import_util37 = __toESM(require("util"), 1); var ERROR_CODES = { ABORTED: "archive was aborted", DIRECTORYDIRPATHREQUIRED: "diretory dirpath argument must be a non-empty string value", @@ -190936,7 +190940,7 @@ function ArchiverError(code, data) { this.code = code; this.data = data; } -import_util38.default.inherits(ArchiverError, Error); +import_util37.default.inherits(ArchiverError, Error); // node_modules/archiver/lib/core.js var import_readable_stream2 = __toESM(require_ours(), 1); @@ -193759,8 +193763,8 @@ async function runWrapper2() { // src/autobuild-action.ts var core17 = __toESM(require_core()); -async function sendCompletedStatusReport(config, logger2, startedAt, allLanguages, failingLanguage, cause) { - initializeEnvironment(getActionVersion()); +async function sendCompletedStatusReport(env, config, logger2, startedAt, allLanguages, failingLanguage, cause) { + env.initialise(getActionVersion()); const status = getActionsStatus(cause, failingLanguage); const statusReportBase = await createStatusReportBase( "autobuild" /* Autobuild */, @@ -193832,6 +193836,7 @@ async function run2({ `We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. ${error3.message}` ); await sendCompletedStatusReport( + env, config, logger2, startedAt, @@ -193842,7 +193847,13 @@ async function run2({ return; } env.export("CODEQL_ACTION_AUTOBUILD_DID_COMPLETE_SUCCESSFULLY" /* AUTOBUILD_DID_COMPLETE_SUCCESSFULLY */, "true"); - await sendCompletedStatusReport(config, logger2, startedAt, languages ?? []); + await sendCompletedStatusReport( + env, + config, + logger2, + startedAt, + languages ?? [] + ); } var autobuild = { name: "autobuild" /* Autobuild */, @@ -193857,7 +193868,7 @@ var fs31 = __toESM(require("fs")); var path25 = __toESM(require("path")); var core19 = __toESM(require_core()); var io7 = __toESM(require_io()); -var semver11 = __toESM(require_semver2()); +var semver12 = __toESM(require_semver2()); // src/config/inputs.ts async function getToolsInput(action, repositoryProperties) { @@ -194410,7 +194421,7 @@ async function run3(actionState) { let toolsSource; let toolsVersion; try { - initializeEnvironment(getActionVersion()); + actionState.env.initialise(getActionVersion()); persistInputs(); apiDetails = { auth: getRequiredInput("token"), @@ -194507,7 +194518,7 @@ async function run3(actionState) { ) { const publicPreview = "2.22.1"; const actualVer = (await codeql.getVersion()).version; - if (semver11.lt(actualVer, publicPreview)) { + if (semver12.lt(actualVer, publicPreview)) { actionState.env.export("CODEQL_ENABLE_EXPERIMENTAL_FEATURES" /* EXPERIMENTAL_FEATURES */, "true"); logger2.info("Experimental Rust analysis enabled"); } @@ -194741,7 +194752,7 @@ exec ${goBinaryPath} "$@"` logger2.debug( `${"CODEQL_EXTRACTOR_JAVA_OPTION_MINIMIZE_DEPENDENCY_JARS" /* JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS */} is already set to '${process.env["CODEQL_EXTRACTOR_JAVA_OPTION_MINIMIZE_DEPENDENCY_JARS" /* JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS */]}', so the Action will not override it.` ); - } else if (await codeQlVersionAtLeast(codeql, CODEQL_VERSION_JAR_MINIMIZATION) && config.dependencyCachingEnabled && config.buildMode === "none" /* None */ && config.languages.includes("java" /* java */)) { + } else if (await codeql.isVersionAtLeast(CODEQL_VERSION_JAR_MINIMIZATION) && config.dependencyCachingEnabled && config.buildMode === "none" /* None */ && config.languages.includes("java" /* java */)) { actionState.env.export( "CODEQL_EXTRACTOR_JAVA_OPTION_MINIMIZE_DEPENDENCY_JARS" /* JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS */, "true" @@ -195478,7 +195489,7 @@ async function run6(actionState) { let toolsSource; let toolsVersion; try { - initializeEnvironment(getActionVersion()); + actionState.env.initialise(getActionVersion()); const apiDetails = { auth: getRequiredInput("token"), externalRepoAuth: getOptionalInput("external-repository-token"), @@ -196430,9 +196441,10 @@ async function sendSuccessStatusReport2(startedAt, uploadStats, logger2) { await sendStatusReport(statusReport); } } -async function run8({ startedAt, logger: logger2 }) { +async function run8(action) { + const logger2 = action.logger; try { - initializeEnvironment(getActionVersion()); + action.env.initialise(getActionVersion()); const gitHubVersion = await getGitHubVersion(); checkActionVersion(getActionVersion(), gitHubVersion); persistInputs(); @@ -196447,7 +196459,7 @@ async function run8({ startedAt, logger: logger2 }) { const startingStatusReportBase = await createStatusReportBase( "upload-sarif" /* UploadSarif */, "starting", - startedAt, + action.startedAt, void 0, await checkDiskUsage(logger2), logger2 @@ -196492,7 +196504,7 @@ async function run8({ startedAt, logger: logger2 }) { } } await sendSuccessStatusReport2( - startedAt, + action.startedAt, codeScanningResult?.statusReport || {}, logger2 ); @@ -196503,7 +196515,7 @@ async function run8({ startedAt, logger: logger2 }) { const errorStatusReportBase = await createStatusReportBase( "upload-sarif" /* UploadSarif */, getActionsStatus(error3), - startedAt, + action.startedAt, void 0, await checkDiskUsage(logger2), logger2, diff --git a/src/actions-util.test.ts b/src/actions-util.test.ts index 175fdea966..1c10b06bfd 100644 --- a/src/actions-util.test.ts +++ b/src/actions-util.test.ts @@ -11,8 +11,8 @@ import { } from "./actions-util"; import { computeAutomationID } from "./api-client"; import { EnvVar } from "./environment"; -import { RecordingLogger, setupTests } from "./testing-utils"; -import { initializeEnvironment, withTmpDir } from "./util"; +import { getTestEnv, RecordingLogger, setupTests } from "./testing-utils"; +import { withTmpDir } from "./util"; setupTests(test); @@ -227,8 +227,9 @@ test.serial( ); test.serial("initializeEnvironment", (t) => { - initializeEnvironment("1.2.3"); - t.deepEqual(process.env[EnvVar.VERSION], "1.2.3"); + const env = getTestEnv(); + env.initialise("1.2.3"); + t.deepEqual(env.getOptional(EnvVar.VERSION), "1.2.3"); }); test.serial("fixCodeQualityCategory", (t) => { diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 23ce54d30f..2127fd4cb0 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -233,7 +233,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) { let databaseUploadResults: DatabaseUploadResult[] = []; try { - util.initializeEnvironment(actionsUtil.getActionVersion()); + action.env.initialise(actionsUtil.getActionVersion()); // Make inputs accessible in the `post` step, details at // https://github.com/github/codeql-action/issues/2553 diff --git a/src/api-client.test.ts b/src/api-client.test.ts index 2bb878f3b7..34ebd52e9d 100644 --- a/src/api-client.test.ts +++ b/src/api-client.test.ts @@ -7,7 +7,7 @@ import { ProxyAgent } from "undici"; import * as actionsUtil from "./actions-util"; import * as api from "./api-client"; import { DO_NOT_RETRY_STATUSES } from "./api-client"; -import { ActionsEnvVars, RegistryProxyVars } from "./environment"; +import { ActionsEnvVars, RegistryProxyVars, getEnv } from "./environment"; import { GITHUB_DOTCOM_API_URL, GITHUB_DOTCOM_URL } from "./github"; import { callee, @@ -21,7 +21,7 @@ import * as util from "./util"; setupTests(test); test.beforeEach(() => { - util.initializeEnvironment(actionsUtil.getActionVersion()); + getEnv().initialise(actionsUtil.getActionVersion()); }); test.serial("getApiClient", async (t) => { diff --git a/src/autobuild-action.ts b/src/autobuild-action.ts index 18aad11855..3e2eb1a3f2 100644 --- a/src/autobuild-action.ts +++ b/src/autobuild-action.ts @@ -10,7 +10,7 @@ import { getGitHubVersion } from "./api-client"; import { determineAutobuildLanguages, runAutobuild } from "./autobuild"; import { getCodeQL } from "./codeql"; import { Config, getConfig } from "./config-utils"; -import { EnvVar } from "./environment"; +import { EnvVar, type Env } from "./environment"; import { Language } from "./languages"; import { Logger } from "./logging"; import { @@ -26,7 +26,6 @@ import { checkDiskUsage, checkGitHubVersionInRange, ConfigurationError, - initializeEnvironment, wrapError, } from "./util"; @@ -38,6 +37,7 @@ interface AutobuildStatusReport extends StatusReportBase { } async function sendCompletedStatusReport( + env: Env, config: Config | undefined, logger: Logger, startedAt: Date, @@ -45,7 +45,7 @@ async function sendCompletedStatusReport( failingLanguage?: string, cause?: Error, ) { - initializeEnvironment(getActionVersion()); + env.initialise(getActionVersion()); const status = getActionsStatus(cause, failingLanguage); const statusReportBase = await createStatusReportBase( @@ -129,6 +129,7 @@ async function run({ `We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. ${error.message}`, ); await sendCompletedStatusReport( + env, config, logger, startedAt, @@ -141,7 +142,13 @@ async function run({ env.export(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true"); - await sendCompletedStatusReport(config, logger, startedAt, languages ?? []); + await sendCompletedStatusReport( + env, + config, + logger, + startedAt, + languages ?? [], + ); } /** Defines the `autobuild` Action. */ diff --git a/src/codeql.test.ts b/src/codeql.test.ts index d702fe438f..d39b9a60d5 100644 --- a/src/codeql.test.ts +++ b/src/codeql.test.ts @@ -21,6 +21,7 @@ import { import type { Config } from "./config-utils"; import * as defaults from "./defaults.json"; import { DocUrl } from "./doc-url"; +import { getEnv } from "./environment"; import { BuiltInLanguage } from "./languages"; import { ToolsSource } from "./setup-codeql"; import { @@ -38,14 +39,13 @@ import { } from "./testing-utils"; import { ToolsDownloadStatusReport } from "./tools-download"; import * as util from "./util"; -import { initializeEnvironment } from "./util"; setupTests(test); let stubConfig: Config; test.beforeEach(() => { - initializeEnvironment("1.2.3"); + getEnv().initialise("1.2.3"); stubConfig = createTestConfig({ languages: [BuiltInLanguage.cpp], diff --git a/src/codeql.ts b/src/codeql.ts index ca93cedf12..c142c537af 100644 --- a/src/codeql.ts +++ b/src/codeql.ts @@ -4,6 +4,7 @@ import * as path from "path"; import * as core from "@actions/core"; import * as toolrunner from "@actions/exec/lib/toolrunner"; import * as yaml from "js-yaml"; +import * as semver from "semver"; import { CommandInvocationError, @@ -19,6 +20,7 @@ import type { ActionConfig } from "./config/action-config"; import { appendExtraQueryExclusions, type Config } from "./config-utils"; import { DocUrl } from "./doc-url"; import { EnvVar, getEnv, Env, ReadOnlyEnv } from "./environment"; +import { getErrorMessage, isDiskConfigurationError } from "./errors"; import { CodeQLDefaultVersionInfo, Feature, @@ -34,7 +36,9 @@ import { ToolsDownloadStatusReport } from "./tools-download"; import { ToolsFeature, isSupportedToolsFeature } from "./tools-features"; import { shouldEnableIndirectTracing } from "./tracer-config"; import * as util from "./util"; -import { BuildMode, CleanupLevel, getErrorMessage } from "./util"; +import { BuildMode, CleanupLevel } from "./util"; + +export { isDiskConfigurationError } from "./errors"; type Options = Array; @@ -70,6 +74,11 @@ export interface CodeQL { * Get a string containing the semver version of the CodeQL executable. */ getVersion(): Promise; + /** + * Determines whether the CLI installation represented by this {@link CodeQL} instance + * has at least the {@link requiredVersion}. + */ + isVersionAtLeast(requiredVersion: string): Promise; /** * Print version information about CodeQL. */ @@ -275,26 +284,6 @@ const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-10-16"; /** The CLI verbosity level to use for extraction in debug mode. */ const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++"; -/** - * Decides whether `e` is a disk-related error outside of our control - * that should be classified as a `ConfigurationError`. - * - * @param e The error to check. - * @returns True if the error should be treated as a `ConfigurationError` or false if not. - */ -export function isDiskConfigurationError(e: unknown): boolean { - if (!(e instanceof Error)) { - return false; - } - - return ( - // out of disk space - e.message.includes("ENOSPC") || - // access denied - e.message.includes("EACCES") - ); -} - /** * Set up CodeQL CLI access. * @@ -403,9 +392,9 @@ export function setCodeQL(codeql: Partial): void { cachedCodeQL = createStubCodeQL(codeql); } -function resolveFunction( +function resolveFunction( partialCodeql: Partial, - methodName: string, + methodName: K, defaultImplementation?: T, ): T { if (typeof partialCodeql[methodName] !== "function") { @@ -415,7 +404,7 @@ function resolveFunction( const dummyMethod = () => { throw new Error(`CodeQL ${methodName} method not correctly defined`); }; - return dummyMethod as T; + return dummyMethod as unknown as T; } return partialCodeql[methodName] as T; } @@ -432,6 +421,19 @@ export function createStubCodeQL(partialCodeql: Partial): CodeQL { getVersion: resolveFunction(partialCodeql, "getVersion", async () => ({ version: "1.0.0", })), + isVersionAtLeast: resolveFunction( + partialCodeql, + "isVersionAtLeast", + async (requiredVersion) => { + return ( + !!partialCodeql.getVersion && + semver.gte( + (await partialCodeql.getVersion()).version, + requiredVersion, + ) + ); + }, + ), printVersion: resolveFunction(partialCodeql, "printVersion"), supportsFeature: resolveFunction( partialCodeql, @@ -525,6 +527,9 @@ export async function getCodeQLForCmd( } return result; }, + async isVersionAtLeast(requiredVersion: string) { + return semver.gte((await this.getVersion()).version, requiredVersion); + }, async printVersion() { // Reuse the cached version information rather than invoking the CLI again. core.info(JSON.stringify(await this.getVersion(), null, 2)); @@ -1062,7 +1067,7 @@ export async function getCodeQLForCmd( // CodeQL object is created. if ( checkVersion && - !(await util.codeQlVersionAtLeast(codeql, CODEQL_MINIMUM_VERSION)) + !(await codeql.isVersionAtLeast(CODEQL_MINIMUM_VERSION)) ) { throw new util.ConfigurationError( `Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${ @@ -1072,7 +1077,7 @@ export async function getCodeQLForCmd( } else if ( checkVersion && env.getOptional(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING) !== "true" && - !(await util.codeQlVersionAtLeast(codeql, CODEQL_NEXT_MINIMUM_VERSION)) + !(await codeql.isVersionAtLeast(CODEQL_NEXT_MINIMUM_VERSION)) ) { const result = await codeql.getVersion(); core.warning( diff --git a/src/config-utils.ts b/src/config-utils.ts index 12c1024f87..b59149e47f 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -82,7 +82,6 @@ import { GitHubVersion, ConfigurationError, BuildMode, - codeQlVersionAtLeast, cloneObject, isDefined, checkDiskUsage, @@ -654,10 +653,7 @@ async function runnerHasSufficientMemory( logger: Logger, ): Promise { if ( - await codeQlVersionAtLeast( - codeql, - CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE, - ) + await codeql.isVersionAtLeast(CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE) ) { logger.debug( `Skipping memory check for overlay analysis because CodeQL version is at least ${CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE}.`, @@ -901,7 +897,7 @@ async function validateOverlayDatabaseMode( ); return new Failure(OverlayDisabledReason.IncompatibleBuildMode); } - if (!(await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION))) { + if (!(await codeql.isVersionAtLeast(CODEQL_OVERLAY_MINIMUM_VERSION))) { logger.warning( `Cannot build an ${overlayDatabaseMode} database because ` + `the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. ` + diff --git a/src/database-upload.test.ts b/src/database-upload.test.ts index 908994112e..7d7145dd36 100644 --- a/src/database-upload.test.ts +++ b/src/database-upload.test.ts @@ -15,6 +15,7 @@ import { cleanupAndUploadDatabases, uploadBundledDatabase, } from "./database-upload"; +import { getEnv } from "./environment"; import { Feature } from "./feature-flags"; import * as gitUtils from "./git-utils"; import { BuiltInLanguage } from "./languages"; @@ -31,18 +32,12 @@ import { setupActionsVars, setupTests, } from "./testing-utils"; -import { - CleanupLevel, - GitHubVariant, - HTTPError, - initializeEnvironment, - withTmpDir, -} from "./util"; +import { CleanupLevel, GitHubVariant, HTTPError, withTmpDir } from "./util"; setupTests(test); test.beforeEach(() => { - initializeEnvironment("1.2.3"); + getEnv().initialise("1.2.3"); }); const testRepoName: RepositoryNwo = { owner: "github", repo: "example" }; diff --git a/src/environment.ts b/src/environment.ts index 7776238e5d..6b885a0fe5 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -397,6 +397,18 @@ export class Env extends ReadOnlyEnv { } } + /** + * Set some initial environment variables that we can set even without + * knowing what version of CodeQL we're running. + */ + public initialise(version: string) { + this.export(EnvVar.FEATURE_MULTI_LANGUAGE, "false"); + this.export(EnvVar.FEATURE_SANDWICH, "false"); + this.export(EnvVar.FEATURE_SARIF_COMBINE, "true"); + this.export(EnvVar.FEATURE_WILL_UPLOAD, "true"); + this.export(EnvVar.VERSION, version); + } + /** Gets a value indicating whether `set` was called at least once. */ public hasChanged(): boolean { return this.changed; diff --git a/src/errors/index.ts b/src/errors/index.ts new file mode 100644 index 0000000000..c2b947d3fa --- /dev/null +++ b/src/errors/index.ts @@ -0,0 +1,88 @@ +import * as json from "../json"; + +/** + * If {@link error} is not already an instance of {@link Error}, then this function constructs + * an {@link Error} with a string representation of {@link error} as the message. + */ +export function wrapError(error: unknown): Error { + return error instanceof Error ? error : new Error(String(error)); +} + +/** + * Returns an appropriate message for the error. + * + * If the error is an {@link Error} instance, this returns the error message without + * an `Error: ` prefix. + */ +export function getErrorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +/** + * Approximates whether {@link error} is like a {@link NodeJS.ErrnoException}. + * We only typically care about the `code` property, so that's what we check for here. + */ +export function isErrnoException( + error: unknown, +): error is NodeJS.ErrnoException { + return ( + typeof error === "object" && + error !== null && + "code" in error && + typeof error.code === "string" + ); +} + +/** + * Decides whether `e` is a disk-related error outside of our control + * that should be classified as a `ConfigurationError`. + * + * @param e The error to check. + * @returns True if the error should be treated as a `ConfigurationError` or false if not. + */ +export function isDiskConfigurationError(e: unknown): boolean { + if (!(e instanceof Error)) { + return false; + } + + return ( + // out of disk space + e.message.includes("ENOSPC") || + // access denied + e.message.includes("EACCES") + ); +} + +/** + * An Error class that indicates an error that occurred due to + * a misconfiguration of the action or the CodeQL CLI. + */ +export class ConfigurationError extends Error {} + +/** Minimal representation of errors resulting from HTTP requests. */ +export class HTTPError extends Error { + public status: number; + + constructor(message: string, status: number) { + super(message); + this.status = status; + } +} + +/** + * Tries to convert {@link arg} to a {@link HTTPError}, but returns `undefined` if + * {@link arg} is not like a {@link HTTPError}. + */ +export function asHTTPError(arg: any): HTTPError | undefined { + if (!json.isObject(arg) || !json.isString(arg.message)) { + return undefined; + } + if (Number.isInteger(arg.status)) { + return new HTTPError(arg.message, arg.status as number); + } + // See https://github.com/actions/toolkit/blob/acb230b99a46ed33a3f04a758cd68b47b9a82908/packages/tool-cache/src/tool-cache.ts#L19 + if (Number.isInteger(arg.httpStatusCode)) { + return new HTTPError(arg.message, arg.httpStatusCode as number); + } + return undefined; +} diff --git a/src/feature-flags.test.ts b/src/feature-flags.test.ts index d8b5eea04d..7b1c1ef3e5 100644 --- a/src/feature-flags.test.ts +++ b/src/feature-flags.test.ts @@ -4,6 +4,7 @@ import * as path from "path"; import test from "ava"; import * as defaults from "./defaults.json"; +import { getEnv } from "./environment"; import { Feature, featureConfig, @@ -26,12 +27,12 @@ import { setupTests, stubFeatureFlagApiEndpoint, } from "./testing-utils"; -import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util"; +import { GitHubVariant, withTmpDir } from "./util"; setupTests(test); test.beforeEach(() => { - initializeEnvironment("1.2.3"); + getEnv().initialise("1.2.3"); }); test.serial( diff --git a/src/feature-flags.ts b/src/feature-flags.ts index a321b941f0..20b7a0263f 100644 --- a/src/feature-flags.ts +++ b/src/feature-flags.ts @@ -560,7 +560,7 @@ class OfflineFeatures implements FeatureEnablement { // Never use this feature if the CLI version explicitly can't support it. const minimumVersion = config.minimumVersion; if (codeql && minimumVersion) { - if (!(await util.codeQlVersionAtLeast(codeql, minimumVersion))) { + if (!(await codeql.isVersionAtLeast(minimumVersion))) { this.logger.debug( `Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum ` + `version ${minimumVersion}.`, diff --git a/src/feature-flags/offline-features.test.ts b/src/feature-flags/offline-features.test.ts index 2870ef3b8a..1c3d2a8c1b 100644 --- a/src/feature-flags/offline-features.test.ts +++ b/src/feature-flags/offline-features.test.ts @@ -8,7 +8,7 @@ import { LoggedMessage, setupTests, } from "../testing-utils"; -import { GitHubVariant, initializeEnvironment, withTmpDir } from "../util"; +import { getEnv, GitHubVariant, withTmpDir } from "../util"; import { assertAllFeaturesHaveDefaultValues, @@ -18,7 +18,7 @@ import { setupTests(test); test.beforeEach(() => { - initializeEnvironment("1.2.3"); + getEnv().initialise("1.2.3"); }); test("OfflineFeatures makes no API requests", async (t) => { diff --git a/src/github.ts b/src/github.ts index 6350fb3f30..e39cddfb05 100644 --- a/src/github.ts +++ b/src/github.ts @@ -1,5 +1,19 @@ import { ActionsEnvVars, type ReadOnlyEnv } from "./environment"; -import { ConfigurationError } from "./util"; +import { ConfigurationError } from "./errors"; + +export enum GitHubVariant { + /** [GitHub.com](https://github.com) */ + DOTCOM = "GitHub.com", + /** [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@latest/admin/overview/about-github-enterprise-server) */ + GHES = "GitHub Enterprise Server", + /** [GitHub Enterprise Cloud with data residency](https://docs.github.com/en/enterprise-cloud@latest/admin/data-residency/about-github-enterprise-cloud-with-data-residency) */ + GHEC_DR = "GitHub Enterprise Cloud with data residency", +} + +export type GitHubVersion = + | { type: GitHubVariant.DOTCOM } + | { type: GitHubVariant.GHEC_DR } + | { type: GitHubVariant.GHES; version: string }; /** A string representing a GitHub instance address. */ export type InstanceURL = string; diff --git a/src/init-action.ts b/src/init-action.ts index af95e8ffab..0998c2e711 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -89,12 +89,10 @@ import { checkDiskUsage, checkForTimeout, checkGitHubVersionInRange, - codeQlVersionAtLeast, DEFAULT_DEBUG_ARTIFACT_NAME, DEFAULT_DEBUG_DATABASE_NAME, getCodeQLMemoryLimit, getThreadsFlagValue, - initializeEnvironment, ConfigurationError, wrapError, checkActionVersion, @@ -227,7 +225,7 @@ async function run( let toolsVersion: string; try { - initializeEnvironment(getActionVersion()); + actionState.env.initialise(getActionVersion()); // Make inputs accessible in the `post` step. persistInputs(); @@ -685,7 +683,7 @@ async function run( `${EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS} is already set to '${process.env[EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS]}', so the Action will not override it.`, ); } else if ( - (await codeQlVersionAtLeast(codeql, CODEQL_VERSION_JAR_MINIMIZATION)) && + (await codeql.isVersionAtLeast(CODEQL_VERSION_JAR_MINIMIZATION)) && config.dependencyCachingEnabled && config.buildMode === BuildMode.None && config.languages.includes(BuiltInLanguage.java) diff --git a/src/setup-codeql-action.ts b/src/setup-codeql-action.ts index 757b26fac5..1bbfdacecc 100644 --- a/src/setup-codeql-action.ts +++ b/src/setup-codeql-action.ts @@ -38,7 +38,6 @@ import { checkDiskUsage, checkForTimeout, checkGitHubVersionInRange, - initializeEnvironment, ConfigurationError, wrapError, checkActionVersion, @@ -108,7 +107,7 @@ async function run( let toolsVersion: string; try { - initializeEnvironment(getActionVersion()); + actionState.env.initialise(getActionVersion()); const apiDetails = { auth: getRequiredInput("token"), diff --git a/src/setup-codeql.test.ts b/src/setup-codeql.test.ts index 6cfd07b3b5..0b2cefc6f4 100644 --- a/src/setup-codeql.test.ts +++ b/src/setup-codeql.test.ts @@ -11,7 +11,13 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import * as api from "./api-client"; import * as diagnostics from "./diagnostics"; -import { ActionsEnvVars, Env, EnvVar, ReadOnlyEnv } from "./environment"; +import { + ActionsEnvVars, + Env, + EnvVar, + getEnv, + ReadOnlyEnv, +} from "./environment"; import { Feature } from "./feature-flags"; import { BuiltInLanguage } from "./languages"; import { getCacheRestoreKeyPrefix } from "./overlay/caching"; @@ -37,18 +43,12 @@ import { setupTests, } from "./testing-utils"; import * as toolsDownload from "./tools-download"; -import { - getErrorMessage, - GitHubVariant, - HTTPError, - initializeEnvironment, - withTmpDir, -} from "./util"; +import { getErrorMessage, GitHubVariant, HTTPError, withTmpDir } from "./util"; setupTests(test); test.beforeEach(() => { - initializeEnvironment("1.2.3"); + getEnv().initialise("1.2.3"); }); function stubDownloadAndExtract() { diff --git a/src/setup/repository.test.ts b/src/setup/repository.test.ts index d1c6d034c0..9fabd84884 100644 --- a/src/setup/repository.test.ts +++ b/src/setup/repository.test.ts @@ -6,7 +6,6 @@ import * as sinon from "sinon"; import * as actionsUtil from "../actions-util"; import { ActionsEnvVars } from "../environment"; import { callee, getTestEnv, setupTests } from "../testing-utils"; -import { initializeEnvironment } from "../util"; import { getCodeQLActionRepository } from "./repository"; @@ -16,7 +15,7 @@ test.serial("getCodeQLActionRepository", async (t) => { const initialEnv = getTestEnv({ [ActionsEnvVars.RUNNER_TEMP]: path.dirname(__dirname), }); - initializeEnvironment("1.2.3", initialEnv); + initialEnv.initialise("1.2.3"); const target = callee(getCodeQLActionRepository) .withArgs() diff --git a/src/setup/repository.ts b/src/setup/repository.ts index 341a278755..ff02a1560b 100644 --- a/src/setup/repository.ts +++ b/src/setup/repository.ts @@ -2,13 +2,12 @@ import { ActionState } from "../action-common"; import { isRunningLocalAction } from "../actions-util"; import * as api from "../api-client"; import { ActionsEnvVars } from "../environment"; -import { GITHUB_DOTCOM_URL } from "../github"; +import { GITHUB_DOTCOM_URL, type InstanceURL } from "../github"; import { isRepositoryNwoStr, parseRepositoryNwo, type RepositoryNwoStr, } from "../repository"; -import { type InstanceURL } from "../util"; /** The NWO of the standard CodeQL Action repository. */ export const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; diff --git a/src/tools-download.test.ts b/src/tools-download.test.ts index 1ba980bbe3..5b146f5060 100644 --- a/src/tools-download.test.ts +++ b/src/tools-download.test.ts @@ -10,6 +10,7 @@ import { https } from "follow-redirects"; import nock from "nock"; import * as sinon from "sinon"; +import * as errors from "./errors"; import * as tar from "./tar"; import { RecordingLogger, setupTests } from "./testing-utils"; import { downloadAndExtract } from "./tools-download"; @@ -163,7 +164,7 @@ test.serial( test.serial( "downloadAndExtract handles an unknown status as a non-HTTP error", async (t) => { - const asHTTPError = sinon.spy(util, "asHTTPError"); + const asHTTPError = sinon.spy(errors, "asHTTPError"); await util.withTmpDir(async (tmpDir) => { sinon.stub(process, "platform").value("linux"); const archivePath = path.join(tmpDir, "codeql-bundle.tar.zst"); diff --git a/src/upload-lib.test.ts b/src/upload-lib.test.ts index ebfc5cd404..4738c07c62 100644 --- a/src/upload-lib.test.ts +++ b/src/upload-lib.test.ts @@ -10,17 +10,18 @@ import * as analyses from "./analyses"; import { AnalysisKind, CodeQuality, CodeScanning } from "./analyses"; import * as api from "./api-client"; import * as diffUtils from "./diff-informed-analysis-utils"; +import { getEnv } from "./environment"; import { Logger } from "./logging"; import * as sarif from "./sarif"; import { RecordingLogger, setupTests } from "./testing-utils"; import * as uploadLib from "./upload-lib"; import { UploadPayload } from "./upload-lib/types"; -import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util"; +import { GitHubVariant, withTmpDir } from "./util"; setupTests(test); test.beforeEach(() => { - initializeEnvironment("1.2.3"); + getEnv().initialise("1.2.3"); }); test.serial("validateSarifFileSchema - valid", (t) => { diff --git a/src/upload-sarif-action.ts b/src/upload-sarif-action.ts index 447314fb10..0efbcdb400 100644 --- a/src/upload-sarif-action.ts +++ b/src/upload-sarif-action.ts @@ -24,7 +24,6 @@ import { ConfigurationError, checkActionVersion, checkDiskUsage, - initializeEnvironment, shouldSkipSarifUpload, wrapError, } from "./util"; @@ -55,11 +54,13 @@ async function sendSuccessStatusReport( } } -async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { +async function run(action: ActionState<["Base", "Env", "Logger"]>) { // To capture errors appropriately, keep as much code within the try-catch as // possible, and only use safe functions outside. + const logger = action.logger; + try { - initializeEnvironment(getActionVersion()); + action.env.initialise(getActionVersion()); const gitHubVersion = await getGitHubVersion(); checkActionVersion(getActionVersion(), gitHubVersion); @@ -79,7 +80,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { const startingStatusReportBase = await createStatusReportBase( ActionName.UploadSarif, "starting", - startedAt, + action.startedAt, undefined, await checkDiskUsage(logger), logger, @@ -137,7 +138,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { // so we can't wait for that here. } await sendSuccessStatusReport( - startedAt, + action.startedAt, codeScanningResult?.statusReport || {}, logger, ); @@ -153,7 +154,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { const errorStatusReportBase = await createStatusReportBase( ActionName.UploadSarif, getActionsStatus(error), - startedAt, + action.startedAt, undefined, await checkDiskUsage(logger), logger, diff --git a/src/util.ts b/src/util.ts index b68824d6e9..533f40ed7f 100644 --- a/src/util.ts +++ b/src/util.ts @@ -20,20 +20,22 @@ import { getRequiredEnvParam, exportEnvVar, getEnv, - type Env, type ReadOnlyEnv, } from "./environment"; -import * as json from "./json"; -import { Language } from "./languages"; -import { Logger } from "./logging"; +import { ConfigurationError, getErrorMessage, wrapError } from "./errors"; +import { GitHubVariant, type GitHubVersion } from "./github"; +import type { Language } from "./languages"; +import type { Logger } from "./logging"; // Re-export for backwards compatibility to avoid updating a lot of imports elsewhere. +export * from "./errors"; export { getRequiredEnvParam, getOptionalEnvVar, getEnv, isInTestMode, } from "./environment"; +export { GitHubVariant, type GitHubVersion } from "./github"; /** * The name of the file containing the base database OIDs, as stored in the @@ -47,9 +49,6 @@ const BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json"; */ const BROKEN_VERSIONS = ["0.0.0-20211207"]; -/** A string representing a GitHub instance. */ -export type InstanceURL = string; - /** * Default name of the debugging artifact. */ @@ -470,20 +469,6 @@ const CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR = let hasBeenWarnedAboutVersion = false; -export enum GitHubVariant { - /** [GitHub.com](https://github.com) */ - DOTCOM = "GitHub.com", - /** [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@latest/admin/overview/about-github-enterprise-server) */ - GHES = "GitHub Enterprise Server", - /** [GitHub Enterprise Cloud with data residency](https://docs.github.com/en/enterprise-cloud@latest/admin/data-residency/about-github-enterprise-cloud-with-data-residency) */ - GHEC_DR = "GitHub Enterprise Cloud with data residency", -} - -export type GitHubVersion = - | { type: GitHubVariant.DOTCOM } - | { type: GitHubVariant.GHEC_DR } - | { type: GitHubVariant.GHES; version: string }; - export function checkGitHubVersionInRange( version: GitHubVersion, logger: Logger, @@ -552,54 +537,6 @@ export function assertNever(value: never): never { throw new ExhaustivityCheckingError(value); } -/** - * Set some initial environment variables that we can set even without - * knowing what version of CodeQL we're running. - */ -export function initializeEnvironment(version: string, env: Env = getEnv()) { - env.export(EnvVar.FEATURE_MULTI_LANGUAGE, "false"); - env.export(EnvVar.FEATURE_SANDWICH, "false"); - env.export(EnvVar.FEATURE_SARIF_COMBINE, "true"); - env.export(EnvVar.FEATURE_WILL_UPLOAD, "true"); - env.export(EnvVar.VERSION, version); -} - -export class HTTPError extends Error { - public status: number; - - constructor(message: string, status: number) { - super(message); - this.status = status; - } -} - -/** - * An Error class that indicates an error that occurred due to - * a misconfiguration of the action or the CodeQL CLI. - */ -export class ConfigurationError extends Error {} - -export function asHTTPError(arg: any): HTTPError | undefined { - if (!json.isObject(arg) || !json.isString(arg.message)) { - return undefined; - } - if (Number.isInteger(arg.status)) { - return new HTTPError(arg.message, arg.status as number); - } - // See https://github.com/actions/toolkit/blob/acb230b99a46ed33a3f04a758cd68b47b9a82908/packages/tool-cache/src/tool-cache.ts#L19 - if (Number.isInteger(arg.httpStatusCode)) { - return new HTTPError(arg.message, arg.httpStatusCode as number); - } - return undefined; -} - -export async function codeQlVersionAtLeast( - codeql: CodeQL, - requiredVersion: string, -): Promise { - return semver.gte((await codeql.getVersion()).version, requiredVersion); -} - export function getBaseDatabaseOidsFilePath( config: ActionConfig<"dbLocation">, ): string { @@ -886,35 +823,6 @@ export function parseMatrixInput( } } -export function wrapError(error: unknown): Error { - return error instanceof Error ? error : new Error(String(error)); -} - -/** - * Returns an appropriate message for the error. - * - * If the error is an `Error` instance, this returns the error message without - * an `Error: ` prefix. - */ -export function getErrorMessage(error: unknown): string { - return error instanceof Error ? error.message : String(error); -} - -/** - * Approximates whether {@link error} is like a {@link NodeJS.ErrnoException}. - * We only typically care about the `code` property, so that's what we check for here. - */ -export function isErrnoException( - error: unknown, -): error is NodeJS.ErrnoException { - return ( - typeof error === "object" && - error !== null && - "code" in error && - typeof error.code === "string" - ); -} - export function prettyPrintPack(pack: Pack) { return `${pack.name}${pack.version ? `@${pack.version}` : ""}${ pack.path ? `:${pack.path}` : ""