mirror of
https://github.com/github/codeql-action.git
synced 2026-10-03 09:14:58 +00:00
Read the CLI version of a release from its assets
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
73
lib/entry-points.js
generated
73
lib/entry-points.js
generated
@@ -26953,7 +26953,7 @@ var require_parse2 = __commonJS({
|
||||
"node_modules/semver/functions/parse.js"(exports2, module2) {
|
||||
"use strict";
|
||||
var SemVer = require_semver();
|
||||
var parse3 = (version, options, throwErrors = false) => {
|
||||
var parse4 = (version, options, throwErrors = false) => {
|
||||
if (version instanceof SemVer) {
|
||||
return version;
|
||||
}
|
||||
@@ -26966,7 +26966,7 @@ var require_parse2 = __commonJS({
|
||||
throw er;
|
||||
}
|
||||
};
|
||||
module2.exports = parse3;
|
||||
module2.exports = parse4;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26974,9 +26974,9 @@ var require_parse2 = __commonJS({
|
||||
var require_valid = __commonJS({
|
||||
"node_modules/semver/functions/valid.js"(exports2, module2) {
|
||||
"use strict";
|
||||
var parse3 = require_parse2();
|
||||
var parse4 = require_parse2();
|
||||
var valid4 = (version, options) => {
|
||||
const v = parse3(version, options);
|
||||
const v = parse4(version, options);
|
||||
return v ? v.version : null;
|
||||
};
|
||||
module2.exports = valid4;
|
||||
@@ -26987,9 +26987,9 @@ var require_valid = __commonJS({
|
||||
var require_clean = __commonJS({
|
||||
"node_modules/semver/functions/clean.js"(exports2, module2) {
|
||||
"use strict";
|
||||
var parse3 = require_parse2();
|
||||
var parse4 = require_parse2();
|
||||
var clean3 = (version, options) => {
|
||||
const s = parse3(version.trim().replace(/^[=v]+/, ""), options);
|
||||
const s = parse4(version.trim().replace(/^[=v]+/, ""), options);
|
||||
return s ? s.version : null;
|
||||
};
|
||||
module2.exports = clean3;
|
||||
@@ -27024,10 +27024,10 @@ var require_inc = __commonJS({
|
||||
var require_diff = __commonJS({
|
||||
"node_modules/semver/functions/diff.js"(exports2, module2) {
|
||||
"use strict";
|
||||
var parse3 = require_parse2();
|
||||
var parse4 = require_parse2();
|
||||
var diff = (version1, version2) => {
|
||||
const v1 = parse3(version1, null, true);
|
||||
const v2 = parse3(version2, null, true);
|
||||
const v1 = parse4(version1, null, true);
|
||||
const v2 = parse4(version2, null, true);
|
||||
const comparison = v1.compare(v2);
|
||||
if (comparison === 0) {
|
||||
return null;
|
||||
@@ -27098,9 +27098,9 @@ var require_patch = __commonJS({
|
||||
var require_prerelease = __commonJS({
|
||||
"node_modules/semver/functions/prerelease.js"(exports2, module2) {
|
||||
"use strict";
|
||||
var parse3 = require_parse2();
|
||||
var parse4 = require_parse2();
|
||||
var prerelease = (version, options) => {
|
||||
const parsed = parse3(version, options);
|
||||
const parsed = parse4(version, options);
|
||||
return parsed && parsed.prerelease.length ? parsed.prerelease : null;
|
||||
};
|
||||
module2.exports = prerelease;
|
||||
@@ -27286,7 +27286,7 @@ var require_coerce = __commonJS({
|
||||
"node_modules/semver/functions/coerce.js"(exports2, module2) {
|
||||
"use strict";
|
||||
var SemVer = require_semver();
|
||||
var parse3 = require_parse2();
|
||||
var parse4 = require_parse2();
|
||||
var { safeRe: re, t } = require_re();
|
||||
var coerce3 = (version, options) => {
|
||||
if (version instanceof SemVer) {
|
||||
@@ -27321,7 +27321,7 @@ var require_coerce = __commonJS({
|
||||
const patch = match2[4] || "0";
|
||||
const prerelease = options.includePrerelease && match2[5] ? `-${match2[5]}` : "";
|
||||
const build2 = options.includePrerelease && match2[6] ? `+${match2[6]}` : "";
|
||||
return parse3(`${major}.${minor}.${patch}${prerelease}${build2}`, options);
|
||||
return parse4(`${major}.${minor}.${patch}${prerelease}${build2}`, options);
|
||||
};
|
||||
module2.exports = coerce3;
|
||||
}
|
||||
@@ -27331,7 +27331,7 @@ var require_coerce = __commonJS({
|
||||
var require_truncate = __commonJS({
|
||||
"node_modules/semver/functions/truncate.js"(exports2, module2) {
|
||||
"use strict";
|
||||
var parse3 = require_parse2();
|
||||
var parse4 = require_parse2();
|
||||
var constants = require_constants6();
|
||||
var SemVer = require_semver();
|
||||
var truncate = (version, truncation, options) => {
|
||||
@@ -27343,7 +27343,7 @@ var require_truncate = __commonJS({
|
||||
};
|
||||
var cloneInputVersion = (version, options) => {
|
||||
const versionStringToParse = version instanceof SemVer ? version.version : version;
|
||||
return parse3(versionStringToParse, options);
|
||||
return parse4(versionStringToParse, options);
|
||||
};
|
||||
var doTruncation = (version, truncation) => {
|
||||
if (isPrerelease(truncation)) {
|
||||
@@ -28387,7 +28387,7 @@ var require_semver2 = __commonJS({
|
||||
var constants = require_constants6();
|
||||
var SemVer = require_semver();
|
||||
var identifiers = require_identifiers();
|
||||
var parse3 = require_parse2();
|
||||
var parse4 = require_parse2();
|
||||
var valid4 = require_valid();
|
||||
var clean3 = require_clean();
|
||||
var inc = require_inc();
|
||||
@@ -28426,7 +28426,7 @@ var require_semver2 = __commonJS({
|
||||
var simplifyRange = require_simplify();
|
||||
var subset = require_subset();
|
||||
module2.exports = {
|
||||
parse: parse3,
|
||||
parse: parse4,
|
||||
valid: valid4,
|
||||
clean: clean3,
|
||||
inc,
|
||||
@@ -32089,9 +32089,9 @@ var require_minimatch = __commonJS({
|
||||
throw new TypeError("pattern is too long");
|
||||
}
|
||||
};
|
||||
Minimatch2.prototype.parse = parse3;
|
||||
Minimatch2.prototype.parse = parse4;
|
||||
var SUBPARSE = {};
|
||||
function parse3(pattern, isSub) {
|
||||
function parse4(pattern, isSub) {
|
||||
assertValidPattern2(pattern);
|
||||
var options = this.options;
|
||||
if (pattern === "**") {
|
||||
@@ -33541,8 +33541,8 @@ var require_semver3 = __commonJS({
|
||||
}
|
||||
}
|
||||
var i;
|
||||
exports2.parse = parse3;
|
||||
function parse3(version, options) {
|
||||
exports2.parse = parse4;
|
||||
function parse4(version, options) {
|
||||
if (!options || typeof options !== "object") {
|
||||
options = {
|
||||
loose: !!options,
|
||||
@@ -33570,12 +33570,12 @@ var require_semver3 = __commonJS({
|
||||
}
|
||||
exports2.valid = valid4;
|
||||
function valid4(version, options) {
|
||||
var v = parse3(version, options);
|
||||
var v = parse4(version, options);
|
||||
return v ? v.version : null;
|
||||
}
|
||||
exports2.clean = clean3;
|
||||
function clean3(version, options) {
|
||||
var s = parse3(version.trim().replace(/^[=v]+/, ""), options);
|
||||
var s = parse4(version.trim().replace(/^[=v]+/, ""), options);
|
||||
return s ? s.version : null;
|
||||
}
|
||||
exports2.SemVer = SemVer;
|
||||
@@ -33811,8 +33811,8 @@ var require_semver3 = __commonJS({
|
||||
if (eq(version1, version2)) {
|
||||
return null;
|
||||
} else {
|
||||
var v1 = parse3(version1);
|
||||
var v2 = parse3(version2);
|
||||
var v1 = parse4(version1);
|
||||
var v2 = parse4(version2);
|
||||
var prefix = "";
|
||||
if (v1.prerelease.length || v2.prerelease.length) {
|
||||
prefix = "pre";
|
||||
@@ -34518,7 +34518,7 @@ var require_semver3 = __commonJS({
|
||||
}
|
||||
exports2.prerelease = prerelease;
|
||||
function prerelease(version, options) {
|
||||
var parsed = parse3(version, options);
|
||||
var parsed = parse4(version, options);
|
||||
return parsed && parsed.prerelease.length ? parsed.prerelease : null;
|
||||
}
|
||||
exports2.intersects = intersects;
|
||||
@@ -34555,7 +34555,7 @@ var require_semver3 = __commonJS({
|
||||
if (match2 === null) {
|
||||
return null;
|
||||
}
|
||||
return parse3(match2[2] + "." + (match2[3] || "0") + "." + (match2[4] || "0"), options);
|
||||
return parse4(match2[2] + "." + (match2[3] || "0") + "." + (match2[4] || "0"), options);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -37255,7 +37255,7 @@ var require_ms = __commonJS({
|
||||
options = options || {};
|
||||
var type = typeof val;
|
||||
if (type === "string" && val.length > 0) {
|
||||
return parse3(val);
|
||||
return parse4(val);
|
||||
} else if (type === "number" && isFinite(val)) {
|
||||
return options.long ? fmtLong(val) : fmtShort(val);
|
||||
}
|
||||
@@ -37263,7 +37263,7 @@ var require_ms = __commonJS({
|
||||
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
||||
);
|
||||
};
|
||||
function parse3(str) {
|
||||
function parse4(str) {
|
||||
str = String(str);
|
||||
if (str.length > 100) {
|
||||
return;
|
||||
@@ -43199,7 +43199,7 @@ var require_deserializationPolicy = __commonJS({
|
||||
return result;
|
||||
}
|
||||
async function deserializeResponseBody(jsonContentTypes, xmlContentTypes, response, options, parseXML) {
|
||||
const parsedResponse = await parse3(jsonContentTypes, xmlContentTypes, response, options, parseXML);
|
||||
const parsedResponse = await parse4(jsonContentTypes, xmlContentTypes, response, options, parseXML);
|
||||
if (!shouldDeserializeResponse(parsedResponse)) {
|
||||
return parsedResponse;
|
||||
}
|
||||
@@ -43300,7 +43300,7 @@ var require_deserializationPolicy = __commonJS({
|
||||
}
|
||||
return { error: error3, shouldReturnResponse: false };
|
||||
}
|
||||
async function parse3(jsonContentTypes, xmlContentTypes, operationResponse, opts, parseXML) {
|
||||
async function parse4(jsonContentTypes, xmlContentTypes, operationResponse, opts, parseXML) {
|
||||
if (!operationResponse.request.streamResponseStatusCodes?.has(operationResponse.status) && operationResponse.bodyAsText) {
|
||||
const text = operationResponse.bodyAsText;
|
||||
const contentType = operationResponse.headers.get("Content-Type") || "";
|
||||
@@ -112628,7 +112628,7 @@ var require_dist_node2 = __commonJS({
|
||||
return template.replace(/\/$/, "");
|
||||
}
|
||||
}
|
||||
function parse3(options) {
|
||||
function parse4(options) {
|
||||
let method = options.method.toUpperCase();
|
||||
let url2 = (options.url || "/").replace(/:([a-z]\w+)/g, "{$1}");
|
||||
let headers = Object.assign({}, options.headers);
|
||||
@@ -112692,7 +112692,7 @@ var require_dist_node2 = __commonJS({
|
||||
);
|
||||
}
|
||||
function endpointWithDefaults2(defaults3, route, options) {
|
||||
return parse3(merge2(defaults3, route, options));
|
||||
return parse4(merge2(defaults3, route, options));
|
||||
}
|
||||
function withDefaults4(oldDefaults, newDefaults) {
|
||||
const DEFAULTS22 = merge2(oldDefaults, newDefaults);
|
||||
@@ -112701,7 +112701,7 @@ var require_dist_node2 = __commonJS({
|
||||
DEFAULTS: DEFAULTS22,
|
||||
defaults: withDefaults4.bind(null, DEFAULTS22),
|
||||
merge: merge2.bind(null, DEFAULTS22),
|
||||
parse: parse3
|
||||
parse: parse4
|
||||
});
|
||||
}
|
||||
var endpoint2 = withDefaults4(null, DEFAULTS2);
|
||||
@@ -116933,7 +116933,7 @@ var require_binary = __commonJS({
|
||||
});
|
||||
return stream2;
|
||||
};
|
||||
exports2.parse = function parse3(buffer) {
|
||||
exports2.parse = function parse4(buffer) {
|
||||
var self2 = words(function(bytes, cb) {
|
||||
return function(name) {
|
||||
if (offset + bytes <= buffer.length) {
|
||||
@@ -151368,7 +151368,8 @@ async function getRelease({ apiClient }, reference) {
|
||||
});
|
||||
return {
|
||||
url: getReleasePageURL(reference),
|
||||
getAssetURL: (name) => release2.assets.find((asset) => asset.name === name)?.url
|
||||
getAssetURL: (name) => release2.assets.find((asset) => asset.name === name)?.url,
|
||||
assetNames: release2.assets.map((asset) => asset.name)
|
||||
};
|
||||
}
|
||||
function getPublicRelease(reference) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
BundleSelectionOptions,
|
||||
getPublicRelease,
|
||||
getRelease,
|
||||
getReleaseCliVersion,
|
||||
parseCodeQLReleaseUrl,
|
||||
selectBundle,
|
||||
} from "./codeql-release";
|
||||
@@ -290,3 +291,32 @@ test("parseCodeQLReleaseUrl excludes archives, REST references and untrusted URL
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("getRelease returns the names of the release's assets", async (t) => {
|
||||
const assetNames = [COMBINED, "cli-version-2.27.2.txt"];
|
||||
const fixture = releaseFixture({ assetNames });
|
||||
const release = await getRelease(fixture.state, REFERENCE);
|
||||
t.deepEqual(release.assetNames, assetNames);
|
||||
});
|
||||
|
||||
test("getReleaseCliVersion prefers an unambiguous marker asset to the tag", (t) => {
|
||||
for (const [tagName, markers, cliVersion] of [
|
||||
[TAG, [], "2.27.1"],
|
||||
[TAG, ["invalid"], "2.27.1"],
|
||||
[TAG, ["2.27.2"], "2.27.2"],
|
||||
[TAG, ["2.27.1", "2.28.0"], undefined],
|
||||
["codeql-bundle-20260101", [], undefined],
|
||||
["run-123", [], undefined],
|
||||
["run-123", ["2.27.2+202601011200"], "2.27.2+202601011200"],
|
||||
] as const) {
|
||||
t.is(
|
||||
getReleaseCliVersion(
|
||||
tagName,
|
||||
[COMBINED, ...markers.map((version) => `cli-version-${version}.txt`)],
|
||||
getRecordingLogger([], { logToConsole: false }),
|
||||
),
|
||||
cliVersion,
|
||||
`${tagName} ${markers.join(",")}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ActionState } from "./action-common";
|
||||
import type { GitHubApiDetails } from "./api-client";
|
||||
import { CodeQLBundle, getCodeQLBundleName } from "./codeql-bundle";
|
||||
import { CODEQL_VERSION_ZSTD_BUNDLE } from "./feature-flags";
|
||||
import { Logger } from "./logging";
|
||||
import {
|
||||
getPerLanguageBundleLanguage,
|
||||
logMissingPerLanguageBundle,
|
||||
@@ -26,6 +27,8 @@ export interface CodeQLRelease {
|
||||
url: string;
|
||||
/** Returns the download URL for an asset, or `undefined` if the release doesn't have it. */
|
||||
getAssetURL(name: string): string | undefined;
|
||||
/** Names of the release's assets, if we looked up the release. */
|
||||
assetNames?: string[];
|
||||
}
|
||||
|
||||
/** A release requested by URL, on this GitHub instance or on GitHub.com. */
|
||||
@@ -86,6 +89,51 @@ export function parseCodeQLReleaseUrl(
|
||||
};
|
||||
}
|
||||
|
||||
function parseCliVersion(value: string): string | undefined {
|
||||
const parsed = semver.parse(value);
|
||||
if (parsed === null) {
|
||||
return undefined;
|
||||
}
|
||||
// semver's normalized version omits build metadata, which distinguishes nightly builds.
|
||||
return (
|
||||
parsed.version + (parsed.build.length ? `+${parsed.build.join(".")}` : "")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CLI version from the release's `cli-version-<version>.txt` asset if it has one, and
|
||||
* otherwise the version in the tag. Returns `undefined` if the release has conflicting markers.
|
||||
*/
|
||||
export function getReleaseCliVersion(
|
||||
tagName: string,
|
||||
assetNames: string[],
|
||||
logger: Logger,
|
||||
): string | undefined {
|
||||
const versions = new Set<string>();
|
||||
for (const name of assetNames) {
|
||||
const match = name.match(/^cli-version-(.+)\.txt$/);
|
||||
if (match === null) {
|
||||
continue;
|
||||
}
|
||||
const version = parseCliVersion(match[1]);
|
||||
if (version !== undefined) {
|
||||
versions.add(version);
|
||||
} else {
|
||||
logger.debug(`Ignoring invalid CLI version marker ${name}.`);
|
||||
}
|
||||
}
|
||||
if (versions.size > 1) {
|
||||
logger.warning(
|
||||
`Release ${tagName} has conflicting CLI version markers. Using a combined CodeQL bundle.`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
if (versions.size === 1) {
|
||||
return versions.values().next().value;
|
||||
}
|
||||
return parseCliVersion(tagName.replace(/^codeql-bundle-/, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a tag for use in a URL path. Slashes stay as path separators, as in GitHub's release URLs
|
||||
* for tags like `build/123`.
|
||||
@@ -121,6 +169,7 @@ export async function getRelease(
|
||||
url: getReleasePageURL(reference),
|
||||
getAssetURL: (name) =>
|
||||
release.assets.find((asset) => asset.name === name)?.url,
|
||||
assetNames: release.assets.map((asset) => asset.name),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user