Pass changed files in code ratehr than by file-system.

This commit is contained in:
Alex Eyers-Taylor
2025-10-09 21:00:58 +01:00
parent 6a32dd9374
commit f030ca35d0
14 changed files with 1266 additions and 1477 deletions
+650 -689
View File
File diff suppressed because it is too large Load Diff
+17 -34
View File
@@ -27720,15 +27720,15 @@ var require_pattern = __commonJS({
exports2.removeDuplicateSlashes = removeDuplicateSlashes;
function partitionAbsoluteAndRelative(patterns) {
const absolute = [];
const relative3 = [];
const relative2 = [];
for (const pattern of patterns) {
if (isAbsolute2(pattern)) {
absolute.push(pattern);
} else {
relative3.push(pattern);
relative2.push(pattern);
}
}
return [absolute, relative3];
return [absolute, relative2];
}
exports2.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
function isAbsolute2(pattern) {
@@ -80536,8 +80536,8 @@ var require_follow_redirects = __commonJS({
}
return parsed;
}
function resolveUrl(relative3, base) {
return useNativeURL ? new URL2(relative3, base) : parseUrl(url2.resolve(base, relative3));
function resolveUrl(relative2, base) {
return useNativeURL ? new URL2(relative2, base) : parseUrl(url2.resolve(base, relative2));
}
function validateUrl(input) {
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
@@ -90918,42 +90918,41 @@ async function readBaseDatabaseOidsFile(config, logger) {
function getBaseDatabaseOidsFilePath(config) {
return path7.join(config.dbLocation, "base-database-oids.json");
}
async function writeOverlayChangesFile(config, sourceRoot, logger) {
async function writeOverlayChangesFile(config, sourceRoot, prDiffChangedFiles, logger) {
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
const originalCount = changedFiles.length;
let forcedAddedCount = 0;
let extraAddedCount = 0;
try {
const forced = getForcedOverlayFilesFromDiff(logger);
if (forced.size > 0) {
if (prDiffChangedFiles && prDiffChangedFiles.size > 0) {
const existing = new Set(changedFiles);
for (const f of forced) {
for (const f of prDiffChangedFiles) {
if (!existing.has(f)) {
if (overlayFileOids[f] !== void 0 || fs6.existsSync(path7.join(sourceRoot, f))) {
existing.add(f);
changedFiles.push(f);
forcedAddedCount++;
extraAddedCount++;
}
}
}
if (forcedAddedCount > 0) {
if (extraAddedCount > 0) {
logger.debug(
`Force-included ${forcedAddedCount} file(s) from diff ranges into overlay: ${changedFiles.slice(-forcedAddedCount).join(", ")}`
`Added ${extraAddedCount} file(s) from PR diff ranges into overlay: ${changedFiles.slice(-extraAddedCount).join(", ")}`
);
} else {
logger.debug(
"All diff range files were already present in natural overlay changes (or none applicable)."
"All diff range files were already present in the diff from the base database."
);
}
}
} catch (e) {
logger.debug(
`Failed while attempting to force-include diff range files in overlay: ${e.message || e}`
`Failed while attempting to add diff range files in overlay: ${e.message || e}`
);
}
logger.info(
`Found ${originalCount} natural changed file(s); force-added ${forcedAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
`Found ${originalCount} natural changed file(s); added from diff ${extraAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
);
const changedFilesJson = JSON.stringify({ changes: changedFiles });
const overlayChangesFile = path7.join(
@@ -90980,23 +90979,6 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
}
return changes;
}
function getForcedOverlayFilesFromDiff(logger) {
const forced = /* @__PURE__ */ new Set();
const diffRanges = readDiffRangesJsonFile(logger);
if (!diffRanges || diffRanges.length === 0) {
return forced;
}
const checkoutPath = getRequiredInput("checkout_path");
for (const r of diffRanges) {
const absPath = r.path;
if (!absPath) continue;
let rel = path7.relative(checkoutPath, absPath);
if (!rel || rel.startsWith("..")) continue;
rel = rel.split(path7.sep).join("/");
forced.add(rel);
}
return forced;
}
var CACHE_VERSION = 1;
var CACHE_PREFIX = "codeql-overlay-base-database";
var MAX_CACHE_OPERATION_MS = 6e5;
@@ -92831,7 +92813,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
async isScannedLanguage(language) {
return !await this.isTracedLanguage(language);
},
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, logger) {
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, prDiffChangedFiles, logger) {
const extraArgs = config.languages.map(
(language) => `--language=${language}`
);
@@ -92866,6 +92848,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
const overlayChangesFile = await writeOverlayChangesFile(
config,
sourceRoot,
prDiffChangedFiles,
logger
);
extraArgs.push(`--overlay-changes=${overlayChangesFile}`);
+220 -259
View File
File diff suppressed because it is too large Load Diff
+39 -56
View File
@@ -27720,15 +27720,15 @@ var require_pattern = __commonJS({
exports2.removeDuplicateSlashes = removeDuplicateSlashes;
function partitionAbsoluteAndRelative(patterns) {
const absolute = [];
const relative3 = [];
const relative2 = [];
for (const pattern of patterns) {
if (isAbsolute2(pattern)) {
absolute.push(pattern);
} else {
relative3.push(pattern);
relative2.push(pattern);
}
}
return [absolute, relative3];
return [absolute, relative2];
}
exports2.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
function isAbsolute2(pattern) {
@@ -80536,8 +80536,8 @@ var require_follow_redirects = __commonJS({
}
return parsed;
}
function resolveUrl(relative3, base) {
return useNativeURL ? new URL2(relative3, base) : parseUrl(url2.resolve(base, relative3));
function resolveUrl(relative2, base) {
return useNativeURL ? new URL2(relative2, base) : parseUrl(url2.resolve(base, relative2));
}
function validateUrl(input) {
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
@@ -84278,8 +84278,8 @@ var require_readdir_glob = __commonJS({
useStat = true;
}
const filename = dir + "/" + name;
const relative3 = filename.slice(1);
const absolute = path19 + "/" + relative3;
const relative2 = filename.slice(1);
const absolute = path19 + "/" + relative2;
let stats = null;
if (useStat || followSymlinks) {
stats = await stat(absolute, followSymlinks);
@@ -84291,12 +84291,12 @@ var require_readdir_glob = __commonJS({
stats = { isDirectory: () => false };
}
if (stats.isDirectory()) {
if (!shouldSkip(relative3)) {
yield { relative: relative3, absolute, stats };
if (!shouldSkip(relative2)) {
yield { relative: relative2, absolute, stats };
yield* exploreWalkAsync(filename, path19, followSymlinks, useStat, shouldSkip, false);
}
} else {
yield { relative: relative3, absolute, stats };
yield { relative: relative2, absolute, stats };
}
}
}
@@ -84366,11 +84366,11 @@ var require_readdir_glob = __commonJS({
}
setTimeout(() => this._next(), 0);
}
_shouldSkipDirectory(relative3) {
return this.skipMatchers.some((m) => m.match(relative3));
_shouldSkipDirectory(relative2) {
return this.skipMatchers.some((m) => m.match(relative2));
}
_fileMatches(relative3, isDirectory2) {
const file = relative3 + (isDirectory2 ? "/" : "");
_fileMatches(relative2, isDirectory2) {
const file = relative2 + (isDirectory2 ? "/" : "");
return (this.matchers.length === 0 || this.matchers.some((m) => m.match(file))) && !this.ignoreMatchers.some((m) => m.match(file)) && (!this.options.nodir || !isDirectory2);
}
_next() {
@@ -84379,16 +84379,16 @@ var require_readdir_glob = __commonJS({
if (!obj.done) {
const isDirectory2 = obj.value.stats.isDirectory();
if (this._fileMatches(obj.value.relative, isDirectory2)) {
let relative3 = obj.value.relative;
let relative2 = obj.value.relative;
let absolute = obj.value.absolute;
if (this.options.mark && isDirectory2) {
relative3 += "/";
relative2 += "/";
absolute += "/";
}
if (this.options.stat) {
this.emit("match", { relative: relative3, absolute, stat: obj.value.stats });
this.emit("match", { relative: relative2, absolute, stat: obj.value.stats });
} else {
this.emit("match", { relative: relative3, absolute });
this.emit("match", { relative: relative2, absolute });
}
}
this._next(this.iterator);
@@ -89873,8 +89873,8 @@ var require_primordials = __commonJS({
ArrayPrototypeIndexOf(self2, el) {
return self2.indexOf(el);
},
ArrayPrototypeJoin(self2, sep6) {
return self2.join(sep6);
ArrayPrototypeJoin(self2, sep5) {
return self2.join(sep5);
},
ArrayPrototypeMap(self2, fn) {
return self2.map(fn);
@@ -101761,7 +101761,7 @@ var require_commonjs16 = __commonJS({
*
* @internal
*/
constructor(cwd = process.cwd(), pathImpl, sep6, { nocase, childrenCacheSize = 16 * 1024, fs: fs20 = defaultFS } = {}) {
constructor(cwd = process.cwd(), pathImpl, sep5, { nocase, childrenCacheSize = 16 * 1024, fs: fs20 = defaultFS } = {}) {
this.#fs = fsFromOption(fs20);
if (cwd instanceof URL || cwd.startsWith("file://")) {
cwd = (0, node_url_1.fileURLToPath)(cwd);
@@ -101772,7 +101772,7 @@ var require_commonjs16 = __commonJS({
this.#resolveCache = new ResolveCache();
this.#resolvePosixCache = new ResolveCache();
this.#children = new ChildrenCache(childrenCacheSize);
const split = cwdPath.substring(this.rootPath.length).split(sep6);
const split = cwdPath.substring(this.rootPath.length).split(sep5);
if (split.length === 1 && !split[0]) {
split.pop();
}
@@ -102615,10 +102615,10 @@ var require_ignore2 = __commonJS({
ignored(p) {
const fullpath = p.fullpath();
const fullpaths = `${fullpath}/`;
const relative3 = p.relative() || ".";
const relatives = `${relative3}/`;
const relative2 = p.relative() || ".";
const relatives = `${relative2}/`;
for (const m of this.relative) {
if (m.match(relative3) || m.match(relatives))
if (m.match(relative2) || m.match(relatives))
return true;
}
for (const m of this.absolute) {
@@ -102629,9 +102629,9 @@ var require_ignore2 = __commonJS({
}
childrenIgnored(p) {
const fullpath = p.fullpath() + "/";
const relative3 = (p.relative() || ".") + "/";
const relative2 = (p.relative() || ".") + "/";
for (const m of this.relativeChildren) {
if (m.match(relative3))
if (m.match(relative2))
return true;
}
for (const m of this.absoluteChildren) {
@@ -129185,42 +129185,41 @@ async function readBaseDatabaseOidsFile(config, logger) {
function getBaseDatabaseOidsFilePath(config) {
return path7.join(config.dbLocation, "base-database-oids.json");
}
async function writeOverlayChangesFile(config, sourceRoot, logger) {
async function writeOverlayChangesFile(config, sourceRoot, prDiffChangedFiles, logger) {
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
const originalCount = changedFiles.length;
let forcedAddedCount = 0;
let extraAddedCount = 0;
try {
const forced = getForcedOverlayFilesFromDiff(logger);
if (forced.size > 0) {
if (prDiffChangedFiles && prDiffChangedFiles.size > 0) {
const existing = new Set(changedFiles);
for (const f of forced) {
for (const f of prDiffChangedFiles) {
if (!existing.has(f)) {
if (overlayFileOids[f] !== void 0 || fs6.existsSync(path7.join(sourceRoot, f))) {
existing.add(f);
changedFiles.push(f);
forcedAddedCount++;
extraAddedCount++;
}
}
}
if (forcedAddedCount > 0) {
if (extraAddedCount > 0) {
logger.debug(
`Force-included ${forcedAddedCount} file(s) from diff ranges into overlay: ${changedFiles.slice(-forcedAddedCount).join(", ")}`
`Added ${extraAddedCount} file(s) from PR diff ranges into overlay: ${changedFiles.slice(-extraAddedCount).join(", ")}`
);
} else {
logger.debug(
"All diff range files were already present in natural overlay changes (or none applicable)."
"All diff range files were already present in the diff from the base database."
);
}
}
} catch (e) {
logger.debug(
`Failed while attempting to force-include diff range files in overlay: ${e.message || e}`
`Failed while attempting to add diff range files in overlay: ${e.message || e}`
);
}
logger.info(
`Found ${originalCount} natural changed file(s); force-added ${forcedAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
`Found ${originalCount} natural changed file(s); added from diff ${extraAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
);
const changedFilesJson = JSON.stringify({ changes: changedFiles });
const overlayChangesFile = path7.join(
@@ -129247,23 +129246,6 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
}
return changes;
}
function getForcedOverlayFilesFromDiff(logger) {
const forced = /* @__PURE__ */ new Set();
const diffRanges = readDiffRangesJsonFile(logger);
if (!diffRanges || diffRanges.length === 0) {
return forced;
}
const checkoutPath = getRequiredInput("checkout_path");
for (const r of diffRanges) {
const absPath = r.path;
if (!absPath) continue;
let rel = path7.relative(checkoutPath, absPath);
if (!rel || rel.startsWith("..")) continue;
rel = rel.split(path7.sep).join("/");
forced.add(rel);
}
return forced;
}
// src/tools-features.ts
var semver3 = __toESM(require_semver2());
@@ -130828,7 +130810,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
async isScannedLanguage(language) {
return !await this.isTracedLanguage(language);
},
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, logger) {
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, prDiffChangedFiles, logger) {
const extraArgs = config.languages.map(
(language) => `--language=${language}`
);
@@ -130863,6 +130845,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
const overlayChangesFile = await writeOverlayChangesFile(
config,
sourceRoot,
prDiffChangedFiles,
logger
);
extraArgs.push(`--overlay-changes=${overlayChangesFile}`);
+31 -55
View File
@@ -29628,15 +29628,15 @@ var require_pattern = __commonJS({
exports2.removeDuplicateSlashes = removeDuplicateSlashes;
function partitionAbsoluteAndRelative(patterns) {
const absolute = [];
const relative3 = [];
const relative2 = [];
for (const pattern of patterns) {
if (isAbsolute3(pattern)) {
absolute.push(pattern);
} else {
relative3.push(pattern);
relative2.push(pattern);
}
}
return [absolute, relative3];
return [absolute, relative2];
}
exports2.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
function isAbsolute3(pattern) {
@@ -81633,8 +81633,8 @@ var require_follow_redirects = __commonJS({
}
return parsed;
}
function resolveUrl(relative3, base) {
return useNativeURL ? new URL2(relative3, base) : parseUrl(url.resolve(base, relative3));
function resolveUrl(relative2, base) {
return useNativeURL ? new URL2(relative2, base) : parseUrl(url.resolve(base, relative2));
}
function validateUrl(input) {
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
@@ -86808,42 +86808,41 @@ async function readBaseDatabaseOidsFile(config, logger) {
function getBaseDatabaseOidsFilePath(config) {
return path8.join(config.dbLocation, "base-database-oids.json");
}
async function writeOverlayChangesFile(config, sourceRoot, logger) {
async function writeOverlayChangesFile(config, sourceRoot, prDiffChangedFiles, logger) {
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
const originalCount = changedFiles.length;
let forcedAddedCount = 0;
let extraAddedCount = 0;
try {
const forced = getForcedOverlayFilesFromDiff(logger);
if (forced.size > 0) {
if (prDiffChangedFiles && prDiffChangedFiles.size > 0) {
const existing = new Set(changedFiles);
for (const f of forced) {
for (const f of prDiffChangedFiles) {
if (!existing.has(f)) {
if (overlayFileOids[f] !== void 0 || fs6.existsSync(path8.join(sourceRoot, f))) {
existing.add(f);
changedFiles.push(f);
forcedAddedCount++;
extraAddedCount++;
}
}
}
if (forcedAddedCount > 0) {
if (extraAddedCount > 0) {
logger.debug(
`Force-included ${forcedAddedCount} file(s) from diff ranges into overlay: ${changedFiles.slice(-forcedAddedCount).join(", ")}`
`Added ${extraAddedCount} file(s) from PR diff ranges into overlay: ${changedFiles.slice(-extraAddedCount).join(", ")}`
);
} else {
logger.debug(
"All diff range files were already present in natural overlay changes (or none applicable)."
"All diff range files were already present in the diff from the base database."
);
}
}
} catch (e) {
logger.debug(
`Failed while attempting to force-include diff range files in overlay: ${e.message || e}`
`Failed while attempting to add diff range files in overlay: ${e.message || e}`
);
}
logger.info(
`Found ${originalCount} natural changed file(s); force-added ${forcedAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
`Found ${originalCount} natural changed file(s); added from diff ${extraAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
);
const changedFilesJson = JSON.stringify({ changes: changedFiles });
const overlayChangesFile = path8.join(
@@ -86870,23 +86869,6 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
}
return changes;
}
function getForcedOverlayFilesFromDiff(logger) {
const forced = /* @__PURE__ */ new Set();
const diffRanges = readDiffRangesJsonFile(logger);
if (!diffRanges || diffRanges.length === 0) {
return forced;
}
const checkoutPath = getRequiredInput("checkout_path");
for (const r of diffRanges) {
const absPath = r.path;
if (!absPath) continue;
let rel = path8.relative(checkoutPath, absPath);
if (!rel || rel.startsWith("..")) continue;
rel = rel.split(path8.sep).join("/");
forced.add(rel);
}
return forced;
}
var CACHE_VERSION = 1;
var CACHE_PREFIX = "codeql-overlay-base-database";
var MAX_CACHE_OPERATION_MS = 6e5;
@@ -87502,19 +87484,6 @@ function writeDiffRangesJsonFile(logger, ranges) {
${jsonContents}`
);
}
function readDiffRangesJsonFile(logger) {
const jsonFilePath = getDiffRangesJsonFilePath();
if (!fs8.existsSync(jsonFilePath)) {
logger.debug(`Diff ranges JSON file does not exist at ${jsonFilePath}`);
return void 0;
}
const jsonContents = fs8.readFileSync(jsonFilePath, "utf8");
logger.debug(
`Read pr-diff-range JSON file from ${jsonFilePath}:
${jsonContents}`
);
return JSON.parse(jsonContents);
}
async function getPullRequestEditedDiffRanges(branches, logger) {
const fileDiffs = await getFileDiffsWithBasehead(branches, logger);
if (fileDiffs === void 0) {
@@ -89780,7 +89749,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
async isScannedLanguage(language) {
return !await this.isTracedLanguage(language);
},
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, logger) {
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, prDiffChangedFiles, logger) {
const extraArgs = config.languages.map(
(language) => `--language=${language}`
);
@@ -89815,6 +89784,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
const overlayChangesFile = await writeOverlayChangesFile(
config,
sourceRoot,
prDiffChangedFiles,
logger
);
extraArgs.push(`--overlay-changes=${overlayChangesFile}`);
@@ -90312,7 +90282,7 @@ async function initConfig2(inputs) {
return await initConfig(inputs);
});
}
async function runDatabaseInitCluster(databaseInitEnvironment, codeql, config, sourceRoot, processName, qlconfigFile, logger) {
async function runDatabaseInitCluster(databaseInitEnvironment, codeql, config, sourceRoot, processName, qlconfigFile, prDiffChangedFiles, logger) {
fs16.mkdirSync(config.dbLocation, { recursive: true });
await wrapEnvironment(
databaseInitEnvironment,
@@ -90321,6 +90291,7 @@ async function runDatabaseInitCluster(databaseInitEnvironment, codeql, config, s
sourceRoot,
processName,
qlconfigFile,
prDiffChangedFiles,
logger
)
);
@@ -90885,6 +90856,7 @@ async function run() {
initializeEnvironment(getActionVersion());
persistInputs();
let config;
let prDiffChangedFiles;
let codeql;
let toolsDownloadStatusReport;
let toolsFeatureFlagsValid;
@@ -91014,7 +90986,7 @@ async function run() {
logger
});
await checkInstallPython311(config.languages, codeql);
await computeAndPersistDiffRangesEarly(codeql, features, logger);
prDiffChangedFiles = await computeAndPersistDiffRanges(codeql, features, logger);
} catch (unwrappedError) {
const error2 = wrapError(unwrappedError);
core13.setFailed(error2.message);
@@ -91242,6 +91214,7 @@ exec ${goBinaryPath} "$@"`
sourceRoot,
"Runner.Worker.exe",
qlconfigFile,
prDiffChangedFiles,
logger
);
if (config.overlayDatabaseMode !== "none" /* None */ && !await checkPacksForOverlayCompatibility(codeql, config, logger)) {
@@ -91259,6 +91232,7 @@ exec ${goBinaryPath} "$@"`
sourceRoot,
"Runner.Worker.exe",
qlconfigFile,
prDiffChangedFiles,
logger
);
}
@@ -91306,31 +91280,33 @@ exec ${goBinaryPath} "$@"`
logger
);
}
async function computeAndPersistDiffRangesEarly(codeql, features, logger) {
async function computeAndPersistDiffRanges(codeql, features, logger) {
try {
await withGroupAsync("Compute PR diff ranges", async () => {
return await withGroupAsync("Compute PR diff ranges", async () => {
const branches = await getDiffInformedAnalysisBranches(
codeql,
features,
logger
);
if (!branches) {
return;
return void 0;
}
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
if (ranges === void 0) {
return;
return void 0;
}
writeDiffRangesJsonFile(logger, ranges);
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
const distinctFiles = new Set(ranges.map((r) => r.path));
logger.info(
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s) for reuse during analyze step.`
`Persisted ${ranges.length} diff range(s) across ${distinctFiles.size} file(s) for reuse during analyze step.`
);
return distinctFiles;
});
} catch (e) {
logger.warning(
`Failed to compute and persist PR diff ranges early: ${getErrorMessage(e)}`
);
return void 0;
}
}
function getTrapCachingEnabled() {
+215 -254
View File
File diff suppressed because it is too large Load Diff
+17 -34
View File
@@ -29017,15 +29017,15 @@ var require_pattern = __commonJS({
exports2.removeDuplicateSlashes = removeDuplicateSlashes;
function partitionAbsoluteAndRelative(patterns) {
const absolute = [];
const relative3 = [];
const relative2 = [];
for (const pattern of patterns) {
if (isAbsolute2(pattern)) {
absolute.push(pattern);
} else {
relative3.push(pattern);
relative2.push(pattern);
}
}
return [absolute, relative3];
return [absolute, relative2];
}
exports2.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
function isAbsolute2(pattern) {
@@ -81833,8 +81833,8 @@ var require_follow_redirects = __commonJS({
}
return parsed;
}
function resolveUrl(relative3, base) {
return useNativeURL ? new URL2(relative3, base) : parseUrl(url2.resolve(base, relative3));
function resolveUrl(relative2, base) {
return useNativeURL ? new URL2(relative2, base) : parseUrl(url2.resolve(base, relative2));
}
function validateUrl(input) {
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
@@ -89289,42 +89289,41 @@ async function readBaseDatabaseOidsFile(config, logger) {
function getBaseDatabaseOidsFilePath(config) {
return path7.join(config.dbLocation, "base-database-oids.json");
}
async function writeOverlayChangesFile(config, sourceRoot, logger) {
async function writeOverlayChangesFile(config, sourceRoot, prDiffChangedFiles, logger) {
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
const originalCount = changedFiles.length;
let forcedAddedCount = 0;
let extraAddedCount = 0;
try {
const forced = getForcedOverlayFilesFromDiff(logger);
if (forced.size > 0) {
if (prDiffChangedFiles && prDiffChangedFiles.size > 0) {
const existing = new Set(changedFiles);
for (const f of forced) {
for (const f of prDiffChangedFiles) {
if (!existing.has(f)) {
if (overlayFileOids[f] !== void 0 || fs5.existsSync(path7.join(sourceRoot, f))) {
existing.add(f);
changedFiles.push(f);
forcedAddedCount++;
extraAddedCount++;
}
}
}
if (forcedAddedCount > 0) {
if (extraAddedCount > 0) {
logger.debug(
`Force-included ${forcedAddedCount} file(s) from diff ranges into overlay: ${changedFiles.slice(-forcedAddedCount).join(", ")}`
`Added ${extraAddedCount} file(s) from PR diff ranges into overlay: ${changedFiles.slice(-extraAddedCount).join(", ")}`
);
} else {
logger.debug(
"All diff range files were already present in natural overlay changes (or none applicable)."
"All diff range files were already present in the diff from the base database."
);
}
}
} catch (e) {
logger.debug(
`Failed while attempting to force-include diff range files in overlay: ${e.message || e}`
`Failed while attempting to add diff range files in overlay: ${e.message || e}`
);
}
logger.info(
`Found ${originalCount} natural changed file(s); force-added ${forcedAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
`Found ${originalCount} natural changed file(s); added from diff ${extraAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
);
const changedFilesJson = JSON.stringify({ changes: changedFiles });
const overlayChangesFile = path7.join(
@@ -89351,23 +89350,6 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
}
return changes;
}
function getForcedOverlayFilesFromDiff(logger) {
const forced = /* @__PURE__ */ new Set();
const diffRanges = readDiffRangesJsonFile(logger);
if (!diffRanges || diffRanges.length === 0) {
return forced;
}
const checkoutPath = getRequiredInput("checkout_path");
for (const r of diffRanges) {
const absPath = r.path;
if (!absPath) continue;
let rel = path7.relative(checkoutPath, absPath);
if (!rel || rel.startsWith("..")) continue;
rel = rel.split(path7.sep).join("/");
forced.add(rel);
}
return forced;
}
// src/tools-features.ts
var semver3 = __toESM(require_semver2());
@@ -90662,7 +90644,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
async isScannedLanguage(language) {
return !await this.isTracedLanguage(language);
},
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, logger) {
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, prDiffChangedFiles, logger) {
const extraArgs = config.languages.map(
(language) => `--language=${language}`
);
@@ -90697,6 +90679,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
const overlayChangesFile = await writeOverlayChangesFile(
config,
sourceRoot,
prDiffChangedFiles,
logger
);
extraArgs.push(`--overlay-changes=${overlayChangesFile}`);
+51 -68
View File
@@ -27720,15 +27720,15 @@ var require_pattern = __commonJS({
exports2.removeDuplicateSlashes = removeDuplicateSlashes;
function partitionAbsoluteAndRelative(patterns) {
const absolute = [];
const relative3 = [];
const relative2 = [];
for (const pattern of patterns) {
if (isAbsolute2(pattern)) {
absolute.push(pattern);
} else {
relative3.push(pattern);
relative2.push(pattern);
}
}
return [absolute, relative3];
return [absolute, relative2];
}
exports2.partitionAbsoluteAndRelative = partitionAbsoluteAndRelative;
function isAbsolute2(pattern) {
@@ -81833,8 +81833,8 @@ var require_follow_redirects = __commonJS({
}
return parsed;
}
function resolveUrl(relative3, base) {
return useNativeURL ? new URL2(relative3, base) : parseUrl(url2.resolve(base, relative3));
function resolveUrl(relative2, base) {
return useNativeURL ? new URL2(relative2, base) : parseUrl(url2.resolve(base, relative2));
}
function validateUrl(input) {
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
@@ -88949,8 +88949,8 @@ function wrapApiConfigurationError(e) {
}
// src/feature-flags.ts
var fs7 = __toESM(require("fs"));
var path9 = __toESM(require("path"));
var fs6 = __toESM(require("fs"));
var path8 = __toESM(require("path"));
var semver3 = __toESM(require_semver2());
// src/defaults.json
@@ -88958,8 +88958,8 @@ var bundleVersion = "codeql-bundle-v2.23.2";
var cliVersion = "2.23.2";
// src/overlay-database-utils.ts
var fs6 = __toESM(require("fs"));
var path8 = __toESM(require("path"));
var fs5 = __toESM(require("fs"));
var path7 = __toESM(require("path"));
var actionsCache = __toESM(require_cache3());
// src/git-utils.ts
@@ -89159,26 +89159,6 @@ async function isAnalyzingDefaultBranch() {
return currentRef === defaultBranch;
}
// src/diff-informed-analysis-utils.ts
var fs5 = __toESM(require("fs"));
var path7 = __toESM(require("path"));
function getDiffRangesJsonFilePath() {
return path7.join(getTemporaryDirectory(), "pr-diff-range.json");
}
function readDiffRangesJsonFile(logger) {
const jsonFilePath = getDiffRangesJsonFilePath();
if (!fs5.existsSync(jsonFilePath)) {
logger.debug(`Diff ranges JSON file does not exist at ${jsonFilePath}`);
return void 0;
}
const jsonContents = fs5.readFileSync(jsonFilePath, "utf8");
logger.debug(
`Read pr-diff-range JSON file from ${jsonFilePath}:
${jsonContents}`
);
return JSON.parse(jsonContents);
}
// src/logging.ts
var core7 = __toESM(require_core());
function getActionsLogger() {
@@ -89204,12 +89184,12 @@ async function writeBaseDatabaseOidsFile(config, sourceRoot) {
const gitFileOids = await getFileOidsUnderPath(sourceRoot);
const gitFileOidsJson = JSON.stringify(gitFileOids);
const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config);
await fs6.promises.writeFile(baseDatabaseOidsFilePath, gitFileOidsJson);
await fs5.promises.writeFile(baseDatabaseOidsFilePath, gitFileOidsJson);
}
async function readBaseDatabaseOidsFile(config, logger) {
const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config);
try {
const contents = await fs6.promises.readFile(
const contents = await fs5.promises.readFile(
baseDatabaseOidsFilePath,
"utf-8"
);
@@ -89222,54 +89202,53 @@ async function readBaseDatabaseOidsFile(config, logger) {
}
}
function getBaseDatabaseOidsFilePath(config) {
return path8.join(config.dbLocation, "base-database-oids.json");
return path7.join(config.dbLocation, "base-database-oids.json");
}
async function writeOverlayChangesFile(config, sourceRoot, logger) {
async function writeOverlayChangesFile(config, sourceRoot, prDiffChangedFiles, logger) {
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
const originalCount = changedFiles.length;
let forcedAddedCount = 0;
let extraAddedCount = 0;
try {
const forced = getForcedOverlayFilesFromDiff(logger);
if (forced.size > 0) {
if (prDiffChangedFiles && prDiffChangedFiles.size > 0) {
const existing = new Set(changedFiles);
for (const f of forced) {
for (const f of prDiffChangedFiles) {
if (!existing.has(f)) {
if (overlayFileOids[f] !== void 0 || fs6.existsSync(path8.join(sourceRoot, f))) {
if (overlayFileOids[f] !== void 0 || fs5.existsSync(path7.join(sourceRoot, f))) {
existing.add(f);
changedFiles.push(f);
forcedAddedCount++;
extraAddedCount++;
}
}
}
if (forcedAddedCount > 0) {
if (extraAddedCount > 0) {
logger.debug(
`Force-included ${forcedAddedCount} file(s) from diff ranges into overlay: ${changedFiles.slice(-forcedAddedCount).join(", ")}`
`Added ${extraAddedCount} file(s) from PR diff ranges into overlay: ${changedFiles.slice(-extraAddedCount).join(", ")}`
);
} else {
logger.debug(
"All diff range files were already present in natural overlay changes (or none applicable)."
"All diff range files were already present in the diff from the base database."
);
}
}
} catch (e) {
logger.debug(
`Failed while attempting to force-include diff range files in overlay: ${e.message || e}`
`Failed while attempting to add diff range files in overlay: ${e.message || e}`
);
}
logger.info(
`Found ${originalCount} natural changed file(s); force-added ${forcedAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
`Found ${originalCount} natural changed file(s); added from diff ${extraAddedCount}; total ${changedFiles.length} under ${sourceRoot}.`
);
const changedFilesJson = JSON.stringify({ changes: changedFiles });
const overlayChangesFile = path8.join(
const overlayChangesFile = path7.join(
getTemporaryDirectory(),
"overlay-changes.json"
);
logger.debug(
`Writing overlay changed files to ${overlayChangesFile}: ${changedFilesJson}`
);
await fs6.promises.writeFile(overlayChangesFile, changedFilesJson);
await fs5.promises.writeFile(overlayChangesFile, changedFilesJson);
return overlayChangesFile;
}
function computeChangedFiles(baseFileOids, overlayFileOids) {
@@ -89286,23 +89265,6 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
}
return changes;
}
function getForcedOverlayFilesFromDiff(logger) {
const forced = /* @__PURE__ */ new Set();
const diffRanges = readDiffRangesJsonFile(logger);
if (!diffRanges || diffRanges.length === 0) {
return forced;
}
const checkoutPath = getRequiredInput("checkout_path");
for (const r of diffRanges) {
const absPath = r.path;
if (!absPath) continue;
let rel = path8.relative(checkoutPath, absPath);
if (!rel || rel.startsWith("..")) continue;
rel = rel.split(path8.sep).join("/");
forced.add(rel);
}
return forced;
}
// src/tools-features.ts
var semver2 = __toESM(require_semver2());
@@ -89495,7 +89457,7 @@ var Features = class {
this.gitHubFeatureFlags = new GitHubFeatureFlags(
gitHubVersion,
repositoryNwo,
path9.join(tempDir, FEATURE_FLAGS_FILE_NAME),
path8.join(tempDir, FEATURE_FLAGS_FILE_NAME),
logger
);
}
@@ -89674,12 +89636,12 @@ var GitHubFeatureFlags = class {
}
async readLocalFlags() {
try {
if (fs7.existsSync(this.featureFlagsFile)) {
if (fs6.existsSync(this.featureFlagsFile)) {
this.logger.debug(
`Loading feature flags from ${this.featureFlagsFile}`
);
return JSON.parse(
fs7.readFileSync(this.featureFlagsFile, "utf8")
fs6.readFileSync(this.featureFlagsFile, "utf8")
);
}
} catch (e) {
@@ -89692,7 +89654,7 @@ var GitHubFeatureFlags = class {
async writeLocalFlags(flags) {
try {
this.logger.debug(`Writing feature flags to ${this.featureFlagsFile}`);
fs7.writeFileSync(this.featureFlagsFile, JSON.stringify(flags));
fs6.writeFileSync(this.featureFlagsFile, JSON.stringify(flags));
} catch (e) {
this.logger.warning(
`Error writing cached feature flags file ${this.featureFlagsFile}: ${e}.`
@@ -89773,6 +89735,26 @@ var PACK_IDENTIFIER_PATTERN = (function() {
return new RegExp(`^${component}/${component}$`);
})();
// src/diff-informed-analysis-utils.ts
var fs7 = __toESM(require("fs"));
var path9 = __toESM(require("path"));
function getDiffRangesJsonFilePath() {
return path9.join(getTemporaryDirectory(), "pr-diff-range.json");
}
function readDiffRangesJsonFile(logger) {
const jsonFilePath = getDiffRangesJsonFilePath();
if (!fs7.existsSync(jsonFilePath)) {
logger.debug(`Diff ranges JSON file does not exist at ${jsonFilePath}`);
return void 0;
}
const jsonContents = fs7.readFileSync(jsonFilePath, "utf8");
logger.debug(
`Read pr-diff-range JSON file from ${jsonFilePath}:
${jsonContents}`
);
return JSON.parse(jsonContents);
}
// src/trap-caching.ts
var actionsCache2 = __toESM(require_cache3());
@@ -91334,7 +91316,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
async isScannedLanguage(language) {
return !await this.isTracedLanguage(language);
},
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, logger) {
async databaseInitCluster(config, sourceRoot, processName, qlconfigFile, prDiffChangedFiles, logger) {
const extraArgs = config.languages.map(
(language) => `--language=${language}`
);
@@ -91369,6 +91351,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
const overlayChangesFile = await writeOverlayChangesFile(
config,
sourceRoot,
prDiffChangedFiles,
logger
);
extraArgs.push(`--overlay-changes=${overlayChangesFile}`);
+4
View File
@@ -517,6 +517,7 @@ const injectedConfigMacro = test.macro({
"",
undefined,
undefined,
undefined,
getRunnerLogger(true),
);
@@ -803,6 +804,7 @@ test("passes a code scanning config AND qlconfig to the CLI", async (t: Executio
"",
undefined,
"/path/to/qlconfig.yml",
undefined,
getRunnerLogger(true),
);
@@ -831,6 +833,7 @@ test("does not pass a qlconfig to the CLI when it is undefined", async (t: Execu
"",
undefined,
undefined, // undefined qlconfigFile
undefined,
getRunnerLogger(true),
);
@@ -1080,6 +1083,7 @@ test("Avoids duplicating --overwrite flag if specified in CODEQL_ACTION_EXTRA_OP
"sourceRoot",
undefined,
undefined,
undefined,
getRunnerLogger(false),
);
+3
View File
@@ -96,6 +96,7 @@ export interface CodeQL {
sourceRoot: string,
processName: string | undefined,
qlconfigFile: string | undefined,
prDiffChangedFiles: Set<string> | undefined,
logger: Logger,
): Promise<void>;
/**
@@ -560,6 +561,7 @@ export async function getCodeQLForCmd(
sourceRoot: string,
processName: string | undefined,
qlconfigFile: string | undefined,
prDiffChangedFiles: Set<string> | undefined,
logger: Logger,
) {
const extraArgs = config.languages.map(
@@ -602,6 +604,7 @@ export async function getCodeQLForCmd(
const overlayChangesFile = await writeOverlayChangesFile(
config,
sourceRoot,
prDiffChangedFiles,
logger,
);
extraArgs.push(`--overlay-changes=${overlayChangesFile}`);
+13 -8
View File
@@ -180,6 +180,7 @@ async function run() {
persistInputs();
let config: configUtils.Config | undefined;
let prDiffChangedFiles: Set<string> | undefined;
let codeql: CodeQL;
let toolsDownloadStatusReport: ToolsDownloadStatusReport | undefined;
let toolsFeatureFlagsValid: boolean | undefined;
@@ -342,7 +343,7 @@ async function run() {
await checkInstallPython311(config.languages, codeql);
await computeAndPersistDiffRangesEarly(codeql, features, logger);
prDiffChangedFiles = await computeAndPersistDiffRanges(codeql, features, logger);
} catch (unwrappedError) {
const error = wrapError(unwrappedError);
core.setFailed(error.message);
@@ -669,6 +670,7 @@ async function run() {
sourceRoot,
"Runner.Worker.exe",
qlconfigFile,
prDiffChangedFiles,
logger,
);
@@ -698,6 +700,7 @@ async function run() {
sourceRoot,
"Runner.Worker.exe",
qlconfigFile,
prDiffChangedFiles,
logger,
);
}
@@ -760,35 +763,37 @@ async function run() {
* is enabled (feature flag + PR context). This writes the standard pr-diff-range.json
* file for later reuse in the analyze step. Failures are logged but non-fatal.
*/
async function computeAndPersistDiffRangesEarly(
async function computeAndPersistDiffRanges(
codeql: CodeQL,
features: Features,
logger: Logger,
): Promise<void> {
): Promise<Set<string> | undefined> {
try {
await withGroupAsync("Compute PR diff ranges", async () => {
return await withGroupAsync("Compute PR diff ranges", async () => {
const branches = await getDiffInformedAnalysisBranches(
codeql,
features,
logger,
);
if (!branches) {
return;
return undefined;
}
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
if (ranges === undefined) {
return;
return undefined;
}
writeDiffRangesJsonFile(logger, ranges);
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
const distinctFiles = new Set(ranges.map((r) => r.path));
logger.info(
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s) for reuse during analyze step.`,
`Persisted ${ranges.length} diff range(s) across ${distinctFiles.size} file(s) for reuse during analyze step.`,
);
return distinctFiles;
});
} catch (e) {
logger.warning(
`Failed to compute and persist PR diff ranges early: ${getErrorMessage(e)}`,
);
return undefined;
}
}
+2
View File
@@ -73,6 +73,7 @@ export async function runDatabaseInitCluster(
sourceRoot: string,
processName: string | undefined,
qlconfigFile: string | undefined,
prDiffChangedFiles: Set<string> | undefined,
logger: Logger,
): Promise<void> {
fs.mkdirSync(config.dbLocation, { recursive: true });
@@ -84,6 +85,7 @@ export async function runDatabaseInitCluster(
sourceRoot,
processName,
qlconfigFile,
prDiffChangedFiles,
logger,
),
);
+1
View File
@@ -69,6 +69,7 @@ test("writeOverlayChangesFile generates correct changes file", async (t) => {
const changesFilePath = await writeOverlayChangesFile(
config,
sourceRoot,
new Set([]), // The PR didn't touch any files
logger,
);
getFileOidsStubForOverlay.restore();
+3 -20
View File
@@ -9,7 +9,6 @@ import { getAutomationID } from "./api-client";
import { type CodeQL } from "./codeql";
import { type Config } from "./config-utils";
import { getCommitOid, getFileOidsUnderPath } from "./git-utils";
import { readDiffRangesJsonFile } from "./diff-informed-analysis-utils";
import { Logger, withGroupAsync } from "./logging";
import {
isInTestMode,
@@ -117,6 +116,7 @@ function getBaseDatabaseOidsFilePath(config: Config): string {
export async function writeOverlayChangesFile(
config: Config,
sourceRoot: string,
prDiffChangedFiles: Set<string> | undefined,
logger: Logger,
): Promise<string> {
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
@@ -128,10 +128,9 @@ export async function writeOverlayChangesFile(
const originalCount = changedFiles.length;
let extraAddedCount = 0;
try {
const diffChangedFiles = getFilesFromDiff(logger);
if (diffChangedFiles.size > 0) {
if (prDiffChangedFiles && prDiffChangedFiles.size > 0) {
const existing = new Set(changedFiles);
for (const f of diffChangedFiles) {
for (const f of prDiffChangedFiles) {
if (!existing.has(f)) {
// Only include if file still exists (added/modified) — skip deleted files that might appear in diff.
if (overlayFileOids[f] !== undefined || fs.existsSync(path.join(sourceRoot, f))) {
@@ -191,22 +190,6 @@ function computeChangedFiles(
return changes;
}
/**
* Derive the set of repository-relative file paths that have at least one edited range
* in the precomputed diff ranges JSON. Returns an empty set if no JSON exists.
*/
function getFilesFromDiff(logger: Logger): Set<string> {
const forced = new Set<string>();
const diffRanges = readDiffRangesJsonFile(logger);
if (!diffRanges || diffRanges.length === 0) {
return forced;
}
for (const r of diffRanges) {
forced.add(r.path);
}
return forced;
}
// Constants for database caching
const CACHE_VERSION = 1;
const CACHE_PREFIX = "codeql-overlay-base-database";