diff --git a/lib/entry-points.js b/lib/entry-points.js index c52cc88f5..e4a956372 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -107096,41 +107096,6 @@ var require_tool_cache = __commonJS({ } }); -// node_modules/fast-deep-equal/index.js -var require_fast_deep_equal = __commonJS({ - "node_modules/fast-deep-equal/index.js"(exports2, module2) { - "use strict"; - module2.exports = function equal(a, b) { - if (a === b) return true; - if (a && b && typeof a == "object" && typeof b == "object") { - if (a.constructor !== b.constructor) return false; - var length, i, keys; - if (Array.isArray(a)) { - length = a.length; - if (length != b.length) return false; - for (i = length; i-- !== 0; ) - if (!equal(a[i], b[i])) return false; - return true; - } - if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags; - if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf(); - if (a.toString !== Object.prototype.toString) return a.toString() === b.toString(); - keys = Object.keys(a); - length = keys.length; - if (length !== Object.keys(b).length) return false; - for (i = length; i-- !== 0; ) - if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false; - for (i = length; i-- !== 0; ) { - var key = keys[i]; - if (!equal(a[key], b[key])) return false; - } - return true; - } - return a !== a && b !== b; - }; - } -}); - // node_modules/follow-redirects/debug.js var require_debug3 = __commonJS({ "node_modules/follow-redirects/debug.js"(exports2, module2) { @@ -175290,7 +175255,6 @@ var fs14 = __toESM(require("fs")); var path13 = __toESM(require("path")); var import_perf_hooks4 = require("perf_hooks"); var toolcache3 = __toESM(require_tool_cache()); -var import_fast_deep_equal = __toESM(require_fast_deep_equal()); var semver9 = __toESM(require_semver2()); // src/codeql-bundle.ts @@ -175757,6 +175721,55 @@ function getCodeQLActionRepository(action) { } return action.env.getRequired("GITHUB_ACTION_REPOSITORY" /* GITHUB_ACTION_REPOSITORY */); } +var DEFAULT_DOWNLOAD_SOURCE = [ + GITHUB_DOTCOM_URL, + CODEQL_DEFAULT_ACTION_REPOSITORY +]; +var isSameDownloadSource = ([srcUrl, srcRepo], [otherUrl, otherRepo]) => { + return srcUrl === otherUrl && srcRepo === otherRepo; +}; +async function getCodeQLAssetDownloadURL(action, apiDetails, tagName, assetName, assetKind = "CodeQL bundle") { + const codeQLActionRepository = getCodeQLActionRepository(action); + const potentialDownloadSources = [ + // This GitHub instance, and this Action. + [apiDetails.url, codeQLActionRepository], + // This GitHub instance, and the canonical Action. + [apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY], + // GitHub.com, and the canonical Action. + DEFAULT_DOWNLOAD_SOURCE + ]; + const uniqueDownloadSources = potentialDownloadSources.filter( + (source, index2, self2) => { + return !self2.slice(0, index2).some((other) => isSameDownloadSource(source, other)); + } + ); + for (const [apiURL, repository] of uniqueDownloadSources) { + if (isSameDownloadSource(DEFAULT_DOWNLOAD_SOURCE, [apiURL, repository])) { + break; + } + const [repositoryOwner, repositoryName] = repository.split("/"); + try { + const release2 = await getApiClient().rest.repos.getReleaseByTag({ + owner: repositoryOwner, + repo: repositoryName, + tag: tagName + }); + for (const asset of release2.data.assets) { + if (asset.name === assetName) { + action.logger.info( + `Found ${assetKind} ${assetName} in ${repository} on ${apiURL} with URL ${asset.url}.` + ); + return asset.url; + } + } + } catch (e) { + action.logger.info( + `Looked for ${assetKind} ${assetName} in ${repository} on ${apiURL} but got error ${e}.` + ); + } + } + return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${assetName}`; +} // src/tar.ts var import_child_process = require("child_process"); @@ -176154,52 +176167,6 @@ var CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies"; var CODEQL_BUNDLE_VERSION_ALIAS = ["linked", "latest"]; var CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"]; var CODEQL_TOOLCACHE_INPUT = "toolcache"; -async function getCodeQLBundleDownloadURL(tagName, apiDetails, codeQLBundleName, logger2) { - const codeQLActionRepository = getCodeQLActionRepository({ - logger: logger2, - env: getEnv() - }); - const potentialDownloadSources = [ - // This GitHub instance, and this Action. - [apiDetails.url, codeQLActionRepository], - // This GitHub instance, and the canonical Action. - [apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY], - // GitHub.com, and the canonical Action. - [GITHUB_DOTCOM_URL, CODEQL_DEFAULT_ACTION_REPOSITORY] - ]; - const uniqueDownloadSources = potentialDownloadSources.filter( - (source, index2, self2) => { - return !self2.slice(0, index2).some((other) => (0, import_fast_deep_equal.default)(source, other)); - } - ); - for (const downloadSource of uniqueDownloadSources) { - const [apiURL, repository] = downloadSource; - if (apiURL === GITHUB_DOTCOM_URL && repository === CODEQL_DEFAULT_ACTION_REPOSITORY) { - break; - } - const [repositoryOwner, repositoryName] = repository.split("/"); - try { - const release2 = await getApiClient().rest.repos.getReleaseByTag({ - owner: repositoryOwner, - repo: repositoryName, - tag: tagName - }); - for (const asset of release2.data.assets) { - if (asset.name === codeQLBundleName) { - logger2.info( - `Found CodeQL bundle ${codeQLBundleName} in ${repository} on ${apiURL} with URL ${asset.url}.` - ); - return asset.url; - } - } - } catch (e) { - logger2.info( - `Looked for CodeQL bundle ${codeQLBundleName} in ${repository} on ${apiURL} but got error ${e}.` - ); - } - } - return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${codeQLBundleName}`; -} function tryGetBundleVersionFromTagName(tagName, logger2) { const match2 = tagName.match(/^codeql-bundle-(.+)$/); if (match2 === null || match2.length < 2) { @@ -176557,9 +176524,10 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, rawLanguages, othe ); } compressionMethod = cliVersion2 !== void 0 && await useZstdBundle(cliVersion2, tarSupportsZstd) ? "zstd" : "gzip"; + const action = { env: getEnv(), logger: logger2 }; const platform2 = getBundlePlatform(); const perLanguageBundleLanguage = await getPerLanguageBundleLanguage( - { env: getEnv(), features, logger: logger2 }, + { ...action, features }, { rawLanguages, otherLanguagePacksReason, @@ -176569,11 +176537,11 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, rawLanguages, othe variant } ); - const resolveBundleURL = (language) => getCodeQLBundleDownloadURL( - bundleTagName, + const resolveBundleURL = (language) => getCodeQLAssetDownloadURL( + action, apiDetails, - getCodeQLBundleName(compressionMethod, platform2, language), - logger2 + bundleTagName, + getCodeQLBundleName(compressionMethod, platform2, language) ); const combinedBundleURL = await resolveBundleURL(); if (perLanguageBundleLanguage !== void 0) { diff --git a/package-lock.json b/package-lock.json index 050ff1e48..d5b4a5c4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,6 @@ "@octokit/plugin-rest-endpoint-methods": "^18.0.0", "@octokit/plugin-retry": "^8.1.1", "archiver": "^8.0.0", - "fast-deep-equal": "^3.1.3", "follow-redirects": "^1.16.0", "get-folder-size": "^5.0.0", "https-proxy-agent": "^7.0.6", @@ -5817,6 +5816,7 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "dev": true, "license": "MIT" }, "node_modules/fast-diff": { diff --git a/package.json b/package.json index 51fd4a450..513f4b528 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "@octokit/plugin-rest-endpoint-methods": "^18.0.0", "@octokit/plugin-retry": "^8.1.1", "archiver": "^8.0.0", - "fast-deep-equal": "^3.1.3", "follow-redirects": "^1.16.0", "get-folder-size": "^5.0.0", "https-proxy-agent": "^7.0.6", diff --git a/src/setup-codeql.ts b/src/setup-codeql.ts index 54117c95d..07666d630 100644 --- a/src/setup-codeql.ts +++ b/src/setup-codeql.ts @@ -4,7 +4,6 @@ import * as path from "path"; import { performance } from "perf_hooks"; import * as toolcache from "@actions/tool-cache"; -import { default as deepEqual } from "fast-deep-equal"; import * as semver from "semver"; import { v4 as uuidV4 } from "uuid"; @@ -35,7 +34,6 @@ import { Feature, FeatureEnablement, } from "./feature-flags"; -import { GITHUB_DOTCOM_URL } from "./github"; import { BuiltInLanguage } from "./languages"; import { Logger } from "./logging"; import { getCodeQlVersionsForOverlayBaseDatabases } from "./overlay/caching"; @@ -44,10 +42,7 @@ import { logPerLanguageBundleFallback, } from "./per-language-bundles"; import { getBundlePlatform } from "./platform"; -import { - CODEQL_DEFAULT_ACTION_REPOSITORY, - getCodeQLActionRepository, -} from "./setup/repository"; +import { getCodeQLAssetDownloadURL } from "./setup/repository"; import * as tar from "./tar"; import { deleteToolcacheBundles, @@ -76,64 +71,6 @@ const CODEQL_BUNDLE_VERSION_ALIAS: string[] = ["linked", "latest"]; const CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"]; const CODEQL_TOOLCACHE_INPUT = "toolcache"; -async function getCodeQLBundleDownloadURL( - tagName: string, - apiDetails: api.GitHubApiDetails, - codeQLBundleName: string, - logger: Logger, -): Promise { - const codeQLActionRepository = getCodeQLActionRepository({ - logger, - env: getEnv(), - }); - const potentialDownloadSources = [ - // This GitHub instance, and this Action. - [apiDetails.url, codeQLActionRepository], - // This GitHub instance, and the canonical Action. - [apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY], - // GitHub.com, and the canonical Action. - [GITHUB_DOTCOM_URL, CODEQL_DEFAULT_ACTION_REPOSITORY], - ]; - // We now filter out any duplicates. - // Duplicates will happen either because the GitHub instance is GitHub.com, or because the Action is not a fork. - const uniqueDownloadSources = potentialDownloadSources.filter( - (source, index, self) => { - return !self.slice(0, index).some((other) => deepEqual(source, other)); - }, - ); - for (const downloadSource of uniqueDownloadSources) { - const [apiURL, repository] = downloadSource; - // If we've reached the final case, short-circuit the API check since we know the bundle exists and is public. - if ( - apiURL === GITHUB_DOTCOM_URL && - repository === CODEQL_DEFAULT_ACTION_REPOSITORY - ) { - break; - } - const [repositoryOwner, repositoryName] = repository.split("/"); - try { - const release = await api.getApiClient().rest.repos.getReleaseByTag({ - owner: repositoryOwner, - repo: repositoryName, - tag: tagName, - }); - for (const asset of release.data.assets) { - if (asset.name === codeQLBundleName) { - logger.info( - `Found CodeQL bundle ${codeQLBundleName} in ${repository} on ${apiURL} with URL ${asset.url}.`, - ); - return asset.url; - } - } - } catch (e) { - logger.info( - `Looked for CodeQL bundle ${codeQLBundleName} in ${repository} on ${apiURL} but got error ${e}.`, - ); - } - } - return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${codeQLBundleName}`; -} - function tryGetBundleVersionFromTagName( tagName: string, logger: Logger, @@ -712,9 +649,10 @@ export async function getCodeQLSource( ? "zstd" : "gzip"; + const action = { env: getEnv(), logger }; const platform = getBundlePlatform(); const perLanguageBundleLanguage = await getPerLanguageBundleLanguage( - { env: getEnv(), features, logger }, + { ...action, features }, { rawLanguages, otherLanguagePacksReason, @@ -727,11 +665,11 @@ export async function getCodeQLSource( // Resolves the combined or per-language bundle URL for the requested release. const resolveBundleURL = (language?: BuiltInLanguage) => - getCodeQLBundleDownloadURL( - bundleTagName, + getCodeQLAssetDownloadURL( + action, apiDetails, + bundleTagName, getCodeQLBundleName(compressionMethod, platform, language), - logger, ); const combinedBundleURL = await resolveBundleURL(); diff --git a/src/setup/repository.ts b/src/setup/repository.ts index c58470630..e2c370f88 100644 --- a/src/setup/repository.ts +++ b/src/setup/repository.ts @@ -1,6 +1,8 @@ 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"; /** The NWO of the standard CodeQL Action repository. */ export const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action"; @@ -28,3 +30,100 @@ export function getCodeQLActionRepository( return action.env.getRequired(ActionsEnvVars.GITHUB_ACTION_REPOSITORY); } + +/**A download source is a pair of strings. */ +export type DownloadSource = [string, string]; + +/** GitHub.com, and the canonical Action. */ +export const DEFAULT_DOWNLOAD_SOURCE: DownloadSource = [ + GITHUB_DOTCOM_URL, + CODEQL_DEFAULT_ACTION_REPOSITORY, +]; + +/** Decides if the two provided download sources are the same. */ +const isSameDownloadSource = ( + [srcUrl, srcRepo]: DownloadSource, + [otherUrl, otherRepo]: DownloadSource, +) => { + return srcUrl === otherUrl && srcRepo === otherRepo; +}; + +/** A download URL is represented as a string. */ +export type DownloadURL = string; + +/** + * Tries to find a download URL for `assetName` in a release tagged with `tagName`. + * + * Depending on where and how the CodeQL Action is running, we may be using different `apiDetails` and there may be + * different options for where to source CodeQL releases from. + * + * This function either returns the download URL for the asset for the first release we find, or + * defaults to the assumed download URL for the asset on the default CodeQL Action repository on GitHub.com. + * In the latter case, this function does not guarantee that the asset actually exists. + * + * @param action The Action state. + * @param apiDetails The details of the GitHub API in use. + * @param tagName The name of the release tag we want to obtain the asset from. + * @param assetName The name of the asset we should look for in the release. + * @param [assetKind="CodeQL bundle"] The kind of asset we are looking for to show in log messages. + * @returns A URL that we can use to download the asset. + */ +export async function getCodeQLAssetDownloadURL( + action: ActionState<["ReadOnlyEnv", "Logger"]>, + apiDetails: api.GitHubApiDetails, + tagName: string, + assetName: string, + assetKind: "CodeQL bundle" = "CodeQL bundle", +): Promise { + const codeQLActionRepository = getCodeQLActionRepository(action); + + const potentialDownloadSources: Array<[string, string]> = [ + // This GitHub instance, and this Action. + [apiDetails.url, codeQLActionRepository], + // This GitHub instance, and the canonical Action. + [apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY], + // GitHub.com, and the canonical Action. + DEFAULT_DOWNLOAD_SOURCE, + ]; + + // We now filter out any duplicates. + // Duplicates will happen either because the GitHub instance is GitHub.com, or because the Action is not a fork. + const uniqueDownloadSources = potentialDownloadSources.filter( + (source, index, self) => { + return !self + .slice(0, index) + .some((other) => isSameDownloadSource(source, other)); + }, + ); + + for (const [apiURL, repository] of uniqueDownloadSources) { + // If we've reached the final case, short-circuit the API check since we know the bundle exists and is public. + if (isSameDownloadSource(DEFAULT_DOWNLOAD_SOURCE, [apiURL, repository])) { + break; + } + + const [repositoryOwner, repositoryName] = repository.split("/"); + try { + const release = await api.getApiClient().rest.repos.getReleaseByTag({ + owner: repositoryOwner, + repo: repositoryName, + tag: tagName, + }); + + for (const asset of release.data.assets) { + if (asset.name === assetName) { + action.logger.info( + `Found ${assetKind} ${assetName} in ${repository} on ${apiURL} with URL ${asset.url}.`, + ); + return asset.url; + } + } + } catch (e) { + action.logger.info( + `Looked for ${assetKind} ${assetName} in ${repository} on ${apiURL} but got error ${e}.`, + ); + } + } + + return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${assetName}`; +}