mirror of
https://github.com/github/codeql-action.git
synced 2026-10-31 18:09:43 +00:00
Refactor getCodeQLBundleDownloadURL out of setup-codeql
This commit is contained in:
@@ -5,7 +5,6 @@ import { performance } from "perf_hooks";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
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";
|
||||
|
||||
@@ -44,10 +43,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 +72,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<string> {
|
||||
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.
|
||||
[util.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 === util.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,
|
||||
@@ -707,9 +645,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,
|
||||
cliVersion,
|
||||
@@ -721,11 +660,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();
|
||||
|
||||
@@ -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 "../util";
|
||||
|
||||
/** 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<DownloadURL> {
|
||||
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}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user