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