mirror of
https://github.com/github/codeql-action.git
synced 2026-04-02 01:32:17 +00:00
feat: always include files from diff in overlay changed files
This commit is contained in:
108
lib/analyze-action-post.js
generated
108
lib/analyze-action-post.js
generated
@@ -100540,8 +100540,8 @@ var require_follow_redirects = __commonJS({
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
function resolveUrl(relative, base) {
|
||||
return useNativeURL ? new URL2(relative, base) : parseUrl2(url.resolve(base, relative));
|
||||
function resolveUrl(relative2, base) {
|
||||
return useNativeURL ? new URL2(relative2, base) : parseUrl2(url.resolve(base, relative2));
|
||||
}
|
||||
function validateUrl(input) {
|
||||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||
@@ -104424,8 +104424,8 @@ var require_readdir_glob = __commonJS({
|
||||
useStat = true;
|
||||
}
|
||||
const filename = dir + "/" + name;
|
||||
const relative = filename.slice(1);
|
||||
const absolute = path7 + "/" + relative;
|
||||
const relative2 = filename.slice(1);
|
||||
const absolute = path7 + "/" + relative2;
|
||||
let stats = null;
|
||||
if (useStat || followSymlinks) {
|
||||
stats = await stat(absolute, followSymlinks);
|
||||
@@ -104437,12 +104437,12 @@ var require_readdir_glob = __commonJS({
|
||||
stats = { isDirectory: () => false };
|
||||
}
|
||||
if (stats.isDirectory()) {
|
||||
if (!shouldSkip(relative)) {
|
||||
yield { relative, absolute, stats };
|
||||
if (!shouldSkip(relative2)) {
|
||||
yield { relative: relative2, absolute, stats };
|
||||
yield* exploreWalkAsync(filename, path7, followSymlinks, useStat, shouldSkip, false);
|
||||
}
|
||||
} else {
|
||||
yield { relative, absolute, stats };
|
||||
yield { relative: relative2, absolute, stats };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104512,11 +104512,11 @@ var require_readdir_glob = __commonJS({
|
||||
}
|
||||
setTimeout(() => this._next(), 0);
|
||||
}
|
||||
_shouldSkipDirectory(relative) {
|
||||
return this.skipMatchers.some((m) => m.match(relative));
|
||||
_shouldSkipDirectory(relative2) {
|
||||
return this.skipMatchers.some((m) => m.match(relative2));
|
||||
}
|
||||
_fileMatches(relative, isDirectory) {
|
||||
const file = relative + (isDirectory ? "/" : "");
|
||||
_fileMatches(relative2, isDirectory) {
|
||||
const file = relative2 + (isDirectory ? "/" : "");
|
||||
return (this.matchers.length === 0 || this.matchers.some((m) => m.match(file))) && !this.ignoreMatchers.some((m) => m.match(file)) && (!this.options.nodir || !isDirectory);
|
||||
}
|
||||
_next() {
|
||||
@@ -104525,16 +104525,16 @@ var require_readdir_glob = __commonJS({
|
||||
if (!obj.done) {
|
||||
const isDirectory = obj.value.stats.isDirectory();
|
||||
if (this._fileMatches(obj.value.relative, isDirectory)) {
|
||||
let relative = obj.value.relative;
|
||||
let relative2 = obj.value.relative;
|
||||
let absolute = obj.value.absolute;
|
||||
if (this.options.mark && isDirectory) {
|
||||
relative += "/";
|
||||
relative2 += "/";
|
||||
absolute += "/";
|
||||
}
|
||||
if (this.options.stat) {
|
||||
this.emit("match", { relative, absolute, stat: obj.value.stats });
|
||||
this.emit("match", { relative: relative2, absolute, stat: obj.value.stats });
|
||||
} else {
|
||||
this.emit("match", { relative, absolute });
|
||||
this.emit("match", { relative: relative2, absolute });
|
||||
}
|
||||
}
|
||||
this._next(this.iterator);
|
||||
@@ -110019,8 +110019,8 @@ var require_primordials = __commonJS({
|
||||
ArrayPrototypeIndexOf(self2, el) {
|
||||
return self2.indexOf(el);
|
||||
},
|
||||
ArrayPrototypeJoin(self2, sep3) {
|
||||
return self2.join(sep3);
|
||||
ArrayPrototypeJoin(self2, sep4) {
|
||||
return self2.join(sep4);
|
||||
},
|
||||
ArrayPrototypeMap(self2, fn) {
|
||||
return self2.map(fn);
|
||||
@@ -122273,7 +122273,7 @@ var require_commonjs23 = __commonJS({
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
constructor(cwd = process.cwd(), pathImpl, sep3, { nocase, childrenCacheSize = 16 * 1024, fs: fs8 = defaultFS } = {}) {
|
||||
constructor(cwd = process.cwd(), pathImpl, sep4, { nocase, childrenCacheSize = 16 * 1024, fs: fs8 = defaultFS } = {}) {
|
||||
this.#fs = fsFromOption(fs8);
|
||||
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
||||
cwd = (0, node_url_1.fileURLToPath)(cwd);
|
||||
@@ -122284,7 +122284,7 @@ var require_commonjs23 = __commonJS({
|
||||
this.#resolveCache = new ResolveCache();
|
||||
this.#resolvePosixCache = new ResolveCache();
|
||||
this.#children = new ChildrenCache(childrenCacheSize);
|
||||
const split = cwdPath.substring(this.rootPath.length).split(sep3);
|
||||
const split = cwdPath.substring(this.rootPath.length).split(sep4);
|
||||
if (split.length === 1 && !split[0]) {
|
||||
split.pop();
|
||||
}
|
||||
@@ -123127,10 +123127,10 @@ var require_ignore = __commonJS({
|
||||
ignored(p) {
|
||||
const fullpath = p.fullpath();
|
||||
const fullpaths = `${fullpath}/`;
|
||||
const relative = p.relative() || ".";
|
||||
const relatives = `${relative}/`;
|
||||
const relative2 = p.relative() || ".";
|
||||
const relatives = `${relative2}/`;
|
||||
for (const m of this.relative) {
|
||||
if (m.match(relative) || m.match(relatives))
|
||||
if (m.match(relative2) || m.match(relatives))
|
||||
return true;
|
||||
}
|
||||
for (const m of this.absolute) {
|
||||
@@ -123141,9 +123141,9 @@ var require_ignore = __commonJS({
|
||||
}
|
||||
childrenIgnored(p) {
|
||||
const fullpath = p.fullpath() + "/";
|
||||
const relative = (p.relative() || ".") + "/";
|
||||
const relative2 = (p.relative() || ".") + "/";
|
||||
for (const m of this.relativeChildren) {
|
||||
if (m.match(relative))
|
||||
if (m.match(relative2))
|
||||
return true;
|
||||
}
|
||||
for (const m of this.absoluteChildren) {
|
||||
@@ -162155,6 +162155,18 @@ var decodeGitFilePath = function(filePath) {
|
||||
}
|
||||
return filePath;
|
||||
};
|
||||
var getGitRoot = async function(sourceRoot) {
|
||||
try {
|
||||
const stdout = await runGitCommand(
|
||||
sourceRoot,
|
||||
["rev-parse", "--show-toplevel"],
|
||||
`Cannot find Git repository root from the source root ${sourceRoot}.`
|
||||
);
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
var getFileOidsUnderPath = async function(basePath) {
|
||||
const stdout = await runGitCommand(
|
||||
basePath,
|
||||
@@ -162277,10 +162289,12 @@ async function readBaseDatabaseOidsFile(config, logger) {
|
||||
async function writeOverlayChangesFile(config, sourceRoot, logger) {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`
|
||||
);
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path2.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -162306,6 +162320,48 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
async function getDiffRangeFilePaths(sourceRoot, logger) {
|
||||
const jsonFilePath = path2.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs2.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs2.readFileSync(jsonFilePath, "utf8"));
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === void 0) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is."
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const sourceRootRelPrefix = path2.relative(repoRoot, sourceRoot).replaceAll(path2.sep, "/");
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// src/tools-features.ts
|
||||
var semver4 = __toESM(require_semver2());
|
||||
|
||||
246
lib/analyze-action.js
generated
246
lib/analyze-action.js
generated
@@ -100540,8 +100540,8 @@ var require_follow_redirects = __commonJS({
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
function resolveUrl(relative2, base) {
|
||||
return useNativeURL ? new URL2(relative2, base) : parseUrl2(url2.resolve(base, relative2));
|
||||
function resolveUrl(relative3, base) {
|
||||
return useNativeURL ? new URL2(relative3, base) : parseUrl2(url2.resolve(base, relative3));
|
||||
}
|
||||
function validateUrl(input) {
|
||||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||
@@ -106859,29 +106859,6 @@ var persistInputs = function() {
|
||||
);
|
||||
core4.saveState(persistedInputsKey, JSON.stringify(inputEnvironmentVariables));
|
||||
};
|
||||
function getPullRequestBranches() {
|
||||
const pullRequest = github.context.payload.pull_request;
|
||||
if (pullRequest) {
|
||||
return {
|
||||
base: pullRequest.base.ref,
|
||||
// We use the head label instead of the head ref here, because the head
|
||||
// ref lacks owner information and by itself does not uniquely identify
|
||||
// the head branch (which may be in a forked repository).
|
||||
head: pullRequest.head.label
|
||||
};
|
||||
}
|
||||
const codeScanningRef = process.env.CODE_SCANNING_REF;
|
||||
const codeScanningBaseBranch = process.env.CODE_SCANNING_BASE_BRANCH;
|
||||
if (codeScanningRef && codeScanningBaseBranch) {
|
||||
return {
|
||||
base: codeScanningBaseBranch,
|
||||
// PR analysis under Default Setup analyzes the PR head commit instead of
|
||||
// the merge commit, so we can use the provided ref directly.
|
||||
head: codeScanningRef
|
||||
};
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
var qualityCategoryMapping = {
|
||||
"c#": "csharp",
|
||||
cpp: "c-cpp",
|
||||
@@ -107775,6 +107752,18 @@ var decodeGitFilePath = function(filePath) {
|
||||
}
|
||||
return filePath;
|
||||
};
|
||||
var getGitRoot = async function(sourceRoot) {
|
||||
try {
|
||||
const stdout = await runGitCommand(
|
||||
sourceRoot,
|
||||
["rev-parse", "--show-toplevel"],
|
||||
`Cannot find Git repository root from the source root ${sourceRoot}.`
|
||||
);
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
var getFileOidsUnderPath = async function(basePath) {
|
||||
const stdout = await runGitCommand(
|
||||
basePath,
|
||||
@@ -107897,10 +107886,12 @@ async function readBaseDatabaseOidsFile(config, logger) {
|
||||
async function writeOverlayChangesFile(config, sourceRoot, logger) {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`
|
||||
);
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path4.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -107926,6 +107917,48 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
async function getDiffRangeFilePaths(sourceRoot, logger) {
|
||||
const jsonFilePath = path4.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs3.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs3.readFileSync(jsonFilePath, "utf8"));
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === void 0) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is."
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const sourceRootRelPrefix = path4.relative(repoRoot, sourceRoot).replaceAll(path4.sep, "/");
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
var CACHE_VERSION = 1;
|
||||
var CACHE_PREFIX = "codeql-overlay-base-database";
|
||||
var MAX_CACHE_OPERATION_MS = 6e5;
|
||||
@@ -108611,34 +108644,9 @@ function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) {
|
||||
}
|
||||
|
||||
// src/diff-informed-analysis-utils.ts
|
||||
async function getDiffInformedAnalysisBranches(codeql, features, logger) {
|
||||
if (!await features.getValue("diff_informed_queries" /* DiffInformedQueries */, codeql)) {
|
||||
return void 0;
|
||||
}
|
||||
const gitHubVersion = await getGitHubVersion();
|
||||
if (gitHubVersion.type === "GitHub Enterprise Server" /* GHES */ && satisfiesGHESVersion(gitHubVersion.version, "<3.19", true)) {
|
||||
return void 0;
|
||||
}
|
||||
const branches = getPullRequestBranches();
|
||||
if (!branches) {
|
||||
logger.info(
|
||||
"Not performing diff-informed analysis because we are not analyzing a pull request."
|
||||
);
|
||||
}
|
||||
return branches;
|
||||
}
|
||||
function getDiffRangesJsonFilePath() {
|
||||
return path6.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
}
|
||||
function writeDiffRangesJsonFile(logger, ranges) {
|
||||
const jsonContents = JSON.stringify(ranges, null, 2);
|
||||
const jsonFilePath = getDiffRangesJsonFilePath();
|
||||
fs5.writeFileSync(jsonFilePath, jsonContents);
|
||||
logger.debug(
|
||||
`Wrote pr-diff-range JSON file to ${jsonFilePath}:
|
||||
${jsonContents}`
|
||||
);
|
||||
}
|
||||
function readDiffRangesJsonFile(logger) {
|
||||
const jsonFilePath = getDiffRangesJsonFilePath();
|
||||
if (!fs5.existsSync(jsonFilePath)) {
|
||||
@@ -108650,118 +108658,15 @@ function readDiffRangesJsonFile(logger) {
|
||||
`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) {
|
||||
return void 0;
|
||||
}
|
||||
if (fileDiffs.length >= 300) {
|
||||
logger.warning(
|
||||
`Cannot retrieve the full diff because there are too many (${fileDiffs.length}) changed files in the pull request.`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
const results = [];
|
||||
for (const filediff of fileDiffs) {
|
||||
const diffRanges = getDiffRanges(filediff, logger);
|
||||
if (diffRanges === void 0) {
|
||||
return void 0;
|
||||
}
|
||||
results.push(...diffRanges);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
async function getFileDiffsWithBasehead(branches, logger) {
|
||||
const repositoryNwo = getRepositoryNwoFromEnv(
|
||||
"CODE_SCANNING_REPOSITORY",
|
||||
"GITHUB_REPOSITORY"
|
||||
);
|
||||
const basehead = `${branches.base}...${branches.head}`;
|
||||
try {
|
||||
const response = await getApiClient().rest.repos.compareCommitsWithBasehead(
|
||||
{
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
basehead,
|
||||
per_page: 1
|
||||
}
|
||||
return JSON.parse(jsonContents);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
logger.debug(
|
||||
`Response from compareCommitsWithBasehead(${basehead}):
|
||||
${JSON.stringify(response, null, 2)}`
|
||||
);
|
||||
return response.data.files;
|
||||
} catch (error3) {
|
||||
if (error3.status) {
|
||||
logger.warning(`Error retrieving diff ${basehead}: ${error3.message}`);
|
||||
logger.debug(
|
||||
`Error running compareCommitsWithBasehead(${basehead}):
|
||||
Request: ${JSON.stringify(error3.request, null, 2)}
|
||||
Error Response: ${JSON.stringify(error3.response, null, 2)}`
|
||||
);
|
||||
return void 0;
|
||||
} else {
|
||||
throw error3;
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
function getDiffRanges(fileDiff, logger) {
|
||||
if (fileDiff.patch === void 0) {
|
||||
if (fileDiff.changes === 0) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
path: fileDiff.filename,
|
||||
startLine: 0,
|
||||
endLine: 0
|
||||
}
|
||||
];
|
||||
}
|
||||
let currentLine = 0;
|
||||
let additionRangeStartLine = void 0;
|
||||
const diffRanges = [];
|
||||
const diffLines = fileDiff.patch.split("\n");
|
||||
diffLines.push(" ");
|
||||
for (const diffLine of diffLines) {
|
||||
if (diffLine.startsWith("-")) {
|
||||
continue;
|
||||
}
|
||||
if (diffLine.startsWith("+")) {
|
||||
if (additionRangeStartLine === void 0) {
|
||||
additionRangeStartLine = currentLine;
|
||||
}
|
||||
currentLine++;
|
||||
continue;
|
||||
}
|
||||
if (additionRangeStartLine !== void 0) {
|
||||
diffRanges.push({
|
||||
path: fileDiff.filename,
|
||||
startLine: additionRangeStartLine,
|
||||
endLine: currentLine - 1
|
||||
});
|
||||
additionRangeStartLine = void 0;
|
||||
}
|
||||
if (diffLine.startsWith("@@ ")) {
|
||||
const match = diffLine.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
||||
if (match === null) {
|
||||
logger.warning(
|
||||
`Cannot parse diff hunk header for ${fileDiff.filename}: ${diffLine}`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
currentLine = parseInt(match[1], 10);
|
||||
continue;
|
||||
}
|
||||
if (diffLine.startsWith(" ")) {
|
||||
currentLine++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return diffRanges;
|
||||
}
|
||||
|
||||
// src/overlay/status.ts
|
||||
var actionsCache2 = __toESM(require_cache5());
|
||||
@@ -110915,14 +110820,17 @@ async function finalizeDatabaseCreation(codeql, features, config, threadsFlag, m
|
||||
trap_import_duration_ms: Math.round(trapImportTime)
|
||||
};
|
||||
}
|
||||
async function setupDiffInformedQueryRun(branches, logger) {
|
||||
async function setupDiffInformedQueryRun(logger) {
|
||||
return await withGroupAsync(
|
||||
"Generating diff range extension pack",
|
||||
async () => {
|
||||
logger.info(
|
||||
`Calculating diff ranges for ${branches.base}...${branches.head}`
|
||||
);
|
||||
const diffRanges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
const diffRanges = readDiffRangesJsonFile(logger);
|
||||
if (diffRanges === void 0) {
|
||||
logger.info(
|
||||
"No precomputed diff ranges found; skipping diff-informed analysis stage."
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
const checkoutPath = getRequiredInput("checkout_path");
|
||||
const packDir = writeDiffRangeDataExtensionPack(
|
||||
logger,
|
||||
@@ -110992,7 +110900,6 @@ dataExtensions:
|
||||
`Wrote pr-diff-range extension pack to ${extensionFilePath}:
|
||||
${extensionContents}`
|
||||
);
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
return diffRangeDir;
|
||||
}
|
||||
var defaultSuites = /* @__PURE__ */ new Set([
|
||||
@@ -113544,12 +113451,7 @@ async function run(startedAt2) {
|
||||
getOptionalInput("ram") || process.env["CODEQL_RAM"],
|
||||
logger
|
||||
);
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger
|
||||
);
|
||||
const diffRangePackDir = branches ? await setupDiffInformedQueryRun(branches, logger) : void 0;
|
||||
const diffRangePackDir = await setupDiffInformedQueryRun(logger);
|
||||
await warnIfGoInstalledAfterInit(config, logger);
|
||||
await runAutobuildIfLegacyGoWorkflow(config, logger);
|
||||
dbCreationTimings = await runFinalize(
|
||||
|
||||
64
lib/autobuild-action.js
generated
64
lib/autobuild-action.js
generated
@@ -100540,8 +100540,8 @@ var require_follow_redirects = __commonJS({
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
function resolveUrl(relative, base) {
|
||||
return useNativeURL ? new URL2(relative, base) : parseUrl2(url.resolve(base, relative));
|
||||
function resolveUrl(relative2, base) {
|
||||
return useNativeURL ? new URL2(relative2, base) : parseUrl2(url.resolve(base, relative2));
|
||||
}
|
||||
function validateUrl(input) {
|
||||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||
@@ -104209,6 +104209,18 @@ var decodeGitFilePath = function(filePath) {
|
||||
}
|
||||
return filePath;
|
||||
};
|
||||
var getGitRoot = async function(sourceRoot) {
|
||||
try {
|
||||
const stdout = await runGitCommand(
|
||||
sourceRoot,
|
||||
["rev-parse", "--show-toplevel"],
|
||||
`Cannot find Git repository root from the source root ${sourceRoot}.`
|
||||
);
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
var getFileOidsUnderPath = async function(basePath) {
|
||||
const stdout = await runGitCommand(
|
||||
basePath,
|
||||
@@ -104331,10 +104343,12 @@ async function readBaseDatabaseOidsFile(config, logger) {
|
||||
async function writeOverlayChangesFile(config, sourceRoot, logger) {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`
|
||||
);
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path2.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -104360,6 +104374,48 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
async function getDiffRangeFilePaths(sourceRoot, logger) {
|
||||
const jsonFilePath = path2.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs2.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs2.readFileSync(jsonFilePath, "utf8"));
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === void 0) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is."
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const sourceRootRelPrefix = path2.relative(repoRoot, sourceRoot).replaceAll(path2.sep, "/");
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// src/tools-features.ts
|
||||
var semver4 = __toESM(require_semver2());
|
||||
|
||||
117
lib/init-action-post.js
generated
117
lib/init-action-post.js
generated
@@ -100540,8 +100540,8 @@ var require_follow_redirects = __commonJS({
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
function resolveUrl(relative2, base) {
|
||||
return useNativeURL ? new URL2(relative2, base) : parseUrl2(url2.resolve(base, relative2));
|
||||
function resolveUrl(relative3, base) {
|
||||
return useNativeURL ? new URL2(relative3, base) : parseUrl2(url2.resolve(base, relative3));
|
||||
}
|
||||
function validateUrl(input) {
|
||||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||
@@ -104424,8 +104424,8 @@ var require_readdir_glob = __commonJS({
|
||||
useStat = true;
|
||||
}
|
||||
const filename = dir + "/" + name;
|
||||
const relative2 = filename.slice(1);
|
||||
const absolute = path19 + "/" + relative2;
|
||||
const relative3 = filename.slice(1);
|
||||
const absolute = path19 + "/" + relative3;
|
||||
let stats = null;
|
||||
if (useStat || followSymlinks) {
|
||||
stats = await stat(absolute, followSymlinks);
|
||||
@@ -104437,12 +104437,12 @@ var require_readdir_glob = __commonJS({
|
||||
stats = { isDirectory: () => false };
|
||||
}
|
||||
if (stats.isDirectory()) {
|
||||
if (!shouldSkip(relative2)) {
|
||||
yield { relative: relative2, absolute, stats };
|
||||
if (!shouldSkip(relative3)) {
|
||||
yield { relative: relative3, absolute, stats };
|
||||
yield* exploreWalkAsync(filename, path19, followSymlinks, useStat, shouldSkip, false);
|
||||
}
|
||||
} else {
|
||||
yield { relative: relative2, absolute, stats };
|
||||
yield { relative: relative3, absolute, stats };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104512,11 +104512,11 @@ var require_readdir_glob = __commonJS({
|
||||
}
|
||||
setTimeout(() => this._next(), 0);
|
||||
}
|
||||
_shouldSkipDirectory(relative2) {
|
||||
return this.skipMatchers.some((m) => m.match(relative2));
|
||||
_shouldSkipDirectory(relative3) {
|
||||
return this.skipMatchers.some((m) => m.match(relative3));
|
||||
}
|
||||
_fileMatches(relative2, isDirectory) {
|
||||
const file = relative2 + (isDirectory ? "/" : "");
|
||||
_fileMatches(relative3, isDirectory) {
|
||||
const file = relative3 + (isDirectory ? "/" : "");
|
||||
return (this.matchers.length === 0 || this.matchers.some((m) => m.match(file))) && !this.ignoreMatchers.some((m) => m.match(file)) && (!this.options.nodir || !isDirectory);
|
||||
}
|
||||
_next() {
|
||||
@@ -104525,16 +104525,16 @@ var require_readdir_glob = __commonJS({
|
||||
if (!obj.done) {
|
||||
const isDirectory = obj.value.stats.isDirectory();
|
||||
if (this._fileMatches(obj.value.relative, isDirectory)) {
|
||||
let relative2 = obj.value.relative;
|
||||
let relative3 = obj.value.relative;
|
||||
let absolute = obj.value.absolute;
|
||||
if (this.options.mark && isDirectory) {
|
||||
relative2 += "/";
|
||||
relative3 += "/";
|
||||
absolute += "/";
|
||||
}
|
||||
if (this.options.stat) {
|
||||
this.emit("match", { relative: relative2, absolute, stat: obj.value.stats });
|
||||
this.emit("match", { relative: relative3, absolute, stat: obj.value.stats });
|
||||
} else {
|
||||
this.emit("match", { relative: relative2, absolute });
|
||||
this.emit("match", { relative: relative3, absolute });
|
||||
}
|
||||
}
|
||||
this._next(this.iterator);
|
||||
@@ -110019,8 +110019,8 @@ var require_primordials = __commonJS({
|
||||
ArrayPrototypeIndexOf(self2, el) {
|
||||
return self2.indexOf(el);
|
||||
},
|
||||
ArrayPrototypeJoin(self2, sep4) {
|
||||
return self2.join(sep4);
|
||||
ArrayPrototypeJoin(self2, sep5) {
|
||||
return self2.join(sep5);
|
||||
},
|
||||
ArrayPrototypeMap(self2, fn) {
|
||||
return self2.map(fn);
|
||||
@@ -122273,7 +122273,7 @@ var require_commonjs23 = __commonJS({
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
constructor(cwd = process.cwd(), pathImpl, sep4, { 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);
|
||||
@@ -122284,7 +122284,7 @@ var require_commonjs23 = __commonJS({
|
||||
this.#resolveCache = new ResolveCache();
|
||||
this.#resolvePosixCache = new ResolveCache();
|
||||
this.#children = new ChildrenCache(childrenCacheSize);
|
||||
const split = cwdPath.substring(this.rootPath.length).split(sep4);
|
||||
const split = cwdPath.substring(this.rootPath.length).split(sep5);
|
||||
if (split.length === 1 && !split[0]) {
|
||||
split.pop();
|
||||
}
|
||||
@@ -123127,10 +123127,10 @@ var require_ignore = __commonJS({
|
||||
ignored(p) {
|
||||
const fullpath = p.fullpath();
|
||||
const fullpaths = `${fullpath}/`;
|
||||
const relative2 = p.relative() || ".";
|
||||
const relatives = `${relative2}/`;
|
||||
const relative3 = p.relative() || ".";
|
||||
const relatives = `${relative3}/`;
|
||||
for (const m of this.relative) {
|
||||
if (m.match(relative2) || m.match(relatives))
|
||||
if (m.match(relative3) || m.match(relatives))
|
||||
return true;
|
||||
}
|
||||
for (const m of this.absolute) {
|
||||
@@ -123141,9 +123141,9 @@ var require_ignore = __commonJS({
|
||||
}
|
||||
childrenIgnored(p) {
|
||||
const fullpath = p.fullpath() + "/";
|
||||
const relative2 = (p.relative() || ".") + "/";
|
||||
const relative3 = (p.relative() || ".") + "/";
|
||||
for (const m of this.relativeChildren) {
|
||||
if (m.match(relative2))
|
||||
if (m.match(relative3))
|
||||
return true;
|
||||
}
|
||||
for (const m of this.absoluteChildren) {
|
||||
@@ -165669,6 +165669,18 @@ var decodeGitFilePath = function(filePath) {
|
||||
}
|
||||
return filePath;
|
||||
};
|
||||
var getGitRoot = async function(sourceRoot) {
|
||||
try {
|
||||
const stdout = await runGitCommand(
|
||||
sourceRoot,
|
||||
["rev-parse", "--show-toplevel"],
|
||||
`Cannot find Git repository root from the source root ${sourceRoot}.`
|
||||
);
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
var getFileOidsUnderPath = async function(basePath) {
|
||||
const stdout = await runGitCommand(
|
||||
basePath,
|
||||
@@ -165791,10 +165803,12 @@ async function readBaseDatabaseOidsFile(config, logger) {
|
||||
async function writeOverlayChangesFile(config, sourceRoot, logger) {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`
|
||||
);
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path4.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -165820,6 +165834,48 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
async function getDiffRangeFilePaths(sourceRoot, logger) {
|
||||
const jsonFilePath = path4.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs3.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs3.readFileSync(jsonFilePath, "utf8"));
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === void 0) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is."
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const sourceRootRelPrefix = path4.relative(repoRoot, sourceRoot).replaceAll(path4.sep, "/");
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// src/tools-features.ts
|
||||
var semver4 = __toESM(require_semver2());
|
||||
@@ -166388,7 +166444,14 @@ function readDiffRangesJsonFile(logger) {
|
||||
`Read pr-diff-range JSON file from ${jsonFilePath}:
|
||||
${jsonContents}`
|
||||
);
|
||||
return JSON.parse(jsonContents);
|
||||
try {
|
||||
return JSON.parse(jsonContents);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
|
||||
// src/overlay/status.ts
|
||||
|
||||
912
lib/init-action.js
generated
912
lib/init-action.js
generated
File diff suppressed because it is too large
Load Diff
64
lib/resolve-environment-action.js
generated
64
lib/resolve-environment-action.js
generated
@@ -100540,8 +100540,8 @@ var require_follow_redirects = __commonJS({
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
function resolveUrl(relative, base) {
|
||||
return useNativeURL ? new URL2(relative, base) : parseUrl2(url.resolve(base, relative));
|
||||
function resolveUrl(relative2, base) {
|
||||
return useNativeURL ? new URL2(relative2, base) : parseUrl2(url.resolve(base, relative2));
|
||||
}
|
||||
function validateUrl(input) {
|
||||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||
@@ -104202,6 +104202,18 @@ var decodeGitFilePath = function(filePath) {
|
||||
}
|
||||
return filePath;
|
||||
};
|
||||
var getGitRoot = async function(sourceRoot) {
|
||||
try {
|
||||
const stdout = await runGitCommand(
|
||||
sourceRoot,
|
||||
["rev-parse", "--show-toplevel"],
|
||||
`Cannot find Git repository root from the source root ${sourceRoot}.`
|
||||
);
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
var getFileOidsUnderPath = async function(basePath) {
|
||||
const stdout = await runGitCommand(
|
||||
basePath,
|
||||
@@ -104324,10 +104336,12 @@ async function readBaseDatabaseOidsFile(config, logger) {
|
||||
async function writeOverlayChangesFile(config, sourceRoot, logger) {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`
|
||||
);
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path2.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -104353,6 +104367,48 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
async function getDiffRangeFilePaths(sourceRoot, logger) {
|
||||
const jsonFilePath = path2.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs2.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs2.readFileSync(jsonFilePath, "utf8"));
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === void 0) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is."
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const sourceRootRelPrefix = path2.relative(repoRoot, sourceRoot).replaceAll(path2.sep, "/");
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// src/tools-features.ts
|
||||
var semver4 = __toESM(require_semver2());
|
||||
|
||||
64
lib/setup-codeql-action.js
generated
64
lib/setup-codeql-action.js
generated
@@ -100540,8 +100540,8 @@ var require_follow_redirects = __commonJS({
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
function resolveUrl(relative2, base) {
|
||||
return useNativeURL ? new URL2(relative2, base) : parseUrl2(url.resolve(base, relative2));
|
||||
function resolveUrl(relative3, base) {
|
||||
return useNativeURL ? new URL2(relative3, base) : parseUrl2(url.resolve(base, relative3));
|
||||
}
|
||||
function validateUrl(input) {
|
||||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||
@@ -104069,6 +104069,18 @@ var decodeGitFilePath = function(filePath) {
|
||||
}
|
||||
return filePath;
|
||||
};
|
||||
var getGitRoot = async function(sourceRoot) {
|
||||
try {
|
||||
const stdout = await runGitCommand(
|
||||
sourceRoot,
|
||||
["rev-parse", "--show-toplevel"],
|
||||
`Cannot find Git repository root from the source root ${sourceRoot}.`
|
||||
);
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
var getFileOidsUnderPath = async function(basePath) {
|
||||
const stdout = await runGitCommand(
|
||||
basePath,
|
||||
@@ -104216,10 +104228,12 @@ async function readBaseDatabaseOidsFile(config, logger) {
|
||||
async function writeOverlayChangesFile(config, sourceRoot, logger) {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`
|
||||
);
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path3.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -104245,6 +104259,48 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
async function getDiffRangeFilePaths(sourceRoot, logger) {
|
||||
const jsonFilePath = path3.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs3.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs3.readFileSync(jsonFilePath, "utf8"));
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === void 0) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is."
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const sourceRootRelPrefix = path3.relative(repoRoot, sourceRoot).replaceAll(path3.sep, "/");
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// src/tools-features.ts
|
||||
var semver3 = __toESM(require_semver2());
|
||||
|
||||
73
lib/upload-lib.js
generated
73
lib/upload-lib.js
generated
@@ -100540,8 +100540,8 @@ var require_follow_redirects = __commonJS({
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
function resolveUrl(relative2, base) {
|
||||
return useNativeURL ? new URL2(relative2, base) : parseUrl2(url2.resolve(base, relative2));
|
||||
function resolveUrl(relative3, base) {
|
||||
return useNativeURL ? new URL2(relative3, base) : parseUrl2(url2.resolve(base, relative3));
|
||||
}
|
||||
function validateUrl(input) {
|
||||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||
@@ -107360,6 +107360,18 @@ var decodeGitFilePath = function(filePath) {
|
||||
}
|
||||
return filePath;
|
||||
};
|
||||
var getGitRoot = async function(sourceRoot) {
|
||||
try {
|
||||
const stdout = await runGitCommand(
|
||||
sourceRoot,
|
||||
["rev-parse", "--show-toplevel"],
|
||||
`Cannot find Git repository root from the source root ${sourceRoot}.`
|
||||
);
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
var getFileOidsUnderPath = async function(basePath) {
|
||||
const stdout = await runGitCommand(
|
||||
basePath,
|
||||
@@ -107482,10 +107494,12 @@ async function readBaseDatabaseOidsFile(config, logger) {
|
||||
async function writeOverlayChangesFile(config, sourceRoot, logger) {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`
|
||||
);
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path4.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -107511,6 +107525,48 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
async function getDiffRangeFilePaths(sourceRoot, logger) {
|
||||
const jsonFilePath = path4.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs3.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs3.readFileSync(jsonFilePath, "utf8"));
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === void 0) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is."
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const sourceRootRelPrefix = path4.relative(repoRoot, sourceRoot).replaceAll(path4.sep, "/");
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// src/tools-features.ts
|
||||
var semver4 = __toESM(require_semver2());
|
||||
@@ -107750,7 +107806,14 @@ function readDiffRangesJsonFile(logger) {
|
||||
`Read pr-diff-range JSON file from ${jsonFilePath}:
|
||||
${jsonContents}`
|
||||
);
|
||||
return JSON.parse(jsonContents);
|
||||
try {
|
||||
return JSON.parse(jsonContents);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
|
||||
// src/overlay/status.ts
|
||||
|
||||
73
lib/upload-sarif-action.js
generated
73
lib/upload-sarif-action.js
generated
@@ -100540,8 +100540,8 @@ var require_follow_redirects = __commonJS({
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
function resolveUrl(relative2, base) {
|
||||
return useNativeURL ? new URL2(relative2, base) : parseUrl2(url2.resolve(base, relative2));
|
||||
function resolveUrl(relative3, base) {
|
||||
return useNativeURL ? new URL2(relative3, base) : parseUrl2(url2.resolve(base, relative3));
|
||||
}
|
||||
function validateUrl(input) {
|
||||
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
||||
@@ -107044,6 +107044,18 @@ var decodeGitFilePath = function(filePath) {
|
||||
}
|
||||
return filePath;
|
||||
};
|
||||
var getGitRoot = async function(sourceRoot) {
|
||||
try {
|
||||
const stdout = await runGitCommand(
|
||||
sourceRoot,
|
||||
["rev-parse", "--show-toplevel"],
|
||||
`Cannot find Git repository root from the source root ${sourceRoot}.`
|
||||
);
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return void 0;
|
||||
}
|
||||
};
|
||||
var getFileOidsUnderPath = async function(basePath) {
|
||||
const stdout = await runGitCommand(
|
||||
basePath,
|
||||
@@ -107191,10 +107203,12 @@ async function readBaseDatabaseOidsFile(config, logger) {
|
||||
async function writeOverlayChangesFile(config, sourceRoot, logger) {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`
|
||||
);
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path3.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -107220,6 +107234,48 @@ function computeChangedFiles(baseFileOids, overlayFileOids) {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
async function getDiffRangeFilePaths(sourceRoot, logger) {
|
||||
const jsonFilePath = path3.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs3.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs3.readFileSync(jsonFilePath, "utf8"));
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === void 0) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is."
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const sourceRootRelPrefix = path3.relative(repoRoot, sourceRoot).replaceAll(path3.sep, "/");
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// src/tools-features.ts
|
||||
var semver3 = __toESM(require_semver2());
|
||||
@@ -107948,7 +108004,14 @@ function readDiffRangesJsonFile(logger) {
|
||||
`Read pr-diff-range JSON file from ${jsonFilePath}:
|
||||
${jsonContents}`
|
||||
);
|
||||
return JSON.parse(jsonContents);
|
||||
try {
|
||||
return JSON.parse(jsonContents);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
}
|
||||
|
||||
// src/overlay/status.ts
|
||||
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
DependencyCacheUploadStatusReport,
|
||||
uploadDependencyCaches,
|
||||
} from "./dependency-caching";
|
||||
import { getDiffInformedAnalysisBranches } from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { initFeatures } from "./feature-flags";
|
||||
import { KnownLanguage } from "./languages";
|
||||
@@ -305,14 +304,8 @@ async function run(startedAt: Date) {
|
||||
logger,
|
||||
);
|
||||
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
const diffRangePackDir = branches
|
||||
? await setupDiffInformedQueryRun(branches, logger)
|
||||
: undefined;
|
||||
// Setup diff informed analysis if needed (based on whether init created the file)
|
||||
const diffRangePackDir = await setupDiffInformedQueryRun(logger);
|
||||
|
||||
await warnIfGoInstalledAfterInit(config, logger);
|
||||
await runAutobuildIfLegacyGoWorkflow(config, logger);
|
||||
|
||||
@@ -5,11 +5,7 @@ import { performance } from "perf_hooks";
|
||||
import * as io from "@actions/io";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
import {
|
||||
getTemporaryDirectory,
|
||||
getRequiredInput,
|
||||
PullRequestBranches,
|
||||
} from "./actions-util";
|
||||
import { getTemporaryDirectory, getRequiredInput } from "./actions-util";
|
||||
import * as analyses from "./analyses";
|
||||
import { setupCppAutobuild } from "./autobuild";
|
||||
import { type CodeQL } from "./codeql";
|
||||
@@ -21,8 +17,7 @@ import {
|
||||
import { addDiagnostic, makeDiagnostic } from "./diagnostics";
|
||||
import {
|
||||
DiffThunkRange,
|
||||
writeDiffRangesJsonFile,
|
||||
getPullRequestEditedDiffRanges,
|
||||
readDiffRangesJsonFile,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { FeatureEnablement, Feature } from "./feature-flags";
|
||||
@@ -237,16 +232,19 @@ async function finalizeDatabaseCreation(
|
||||
* the diff range information, or `undefined` if the feature is disabled.
|
||||
*/
|
||||
export async function setupDiffInformedQueryRun(
|
||||
branches: PullRequestBranches,
|
||||
logger: Logger,
|
||||
): Promise<string | undefined> {
|
||||
return await withGroupAsync(
|
||||
"Generating diff range extension pack",
|
||||
async () => {
|
||||
logger.info(
|
||||
`Calculating diff ranges for ${branches.base}...${branches.head}`,
|
||||
);
|
||||
const diffRanges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
const diffRanges = readDiffRangesJsonFile(logger);
|
||||
if (diffRanges === undefined) {
|
||||
logger.info(
|
||||
"No precomputed diff ranges found; skipping diff-informed analysis stage.",
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const checkoutPath = getRequiredInput("checkout_path");
|
||||
const packDir = writeDiffRangeDataExtensionPack(
|
||||
logger,
|
||||
@@ -368,10 +366,6 @@ dataExtensions:
|
||||
`Wrote pr-diff-range extension pack to ${extensionFilePath}:\n${extensionContents}`,
|
||||
);
|
||||
|
||||
// Write the diff ranges to a JSON file, for action-side alert filtering by the
|
||||
// upload-lib module.
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
|
||||
return diffRangeDir;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,14 @@ export function readDiffRangesJsonFile(
|
||||
logger.debug(
|
||||
`Read pr-diff-range JSON file from ${jsonFilePath}:\n${jsonContents}`,
|
||||
);
|
||||
return JSON.parse(jsonContents) as DiffThunkRange[];
|
||||
try {
|
||||
return JSON.parse(jsonContents) as DiffThunkRange[];
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,11 @@ import {
|
||||
makeDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import {
|
||||
getDiffInformedAnalysisBranches,
|
||||
getPullRequestEditedDiffRanges,
|
||||
writeDiffRangesJsonFile,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
|
||||
import {
|
||||
@@ -54,7 +59,7 @@ import {
|
||||
runDatabaseInitCluster,
|
||||
} from "./init";
|
||||
import { JavaEnvVars, KnownLanguage } from "./languages";
|
||||
import { getActionsLogger, Logger } from "./logging";
|
||||
import { getActionsLogger, Logger, withGroupAsync } from "./logging";
|
||||
import {
|
||||
downloadOverlayBaseDatabaseFromCache,
|
||||
OverlayBaseDatabaseDownloadStats,
|
||||
@@ -413,6 +418,7 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
|
||||
await checkInstallPython311(config.languages, codeql);
|
||||
await computeAndPersistDiffRanges(codeql, features, logger);
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
core.setFailed(error.message);
|
||||
@@ -833,6 +839,42 @@ async function loadRepositoryProperties(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and persist diff ranges when diff-informed analysis 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 computeAndPersistDiffRanges(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
try {
|
||||
await withGroupAsync("Compute PR diff ranges", async () => {
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
if (!branches) {
|
||||
return;
|
||||
}
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === undefined) {
|
||||
return;
|
||||
}
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
|
||||
logger.info(
|
||||
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s).`,
|
||||
);
|
||||
});
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to compute and persist PR diff ranges: ${getErrorMessage(e)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
async function recordZstdAvailability(
|
||||
config: configUtils.Config,
|
||||
zstdAvailability: ZstdAvailability,
|
||||
|
||||
@@ -34,12 +34,14 @@ test.serial(
|
||||
"writeOverlayChangesFile generates correct changes file",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
const dbLocation = path.join(tmpDir, "db");
|
||||
await fs.promises.mkdir(dbLocation, { recursive: true });
|
||||
const sourceRoot = path.join(tmpDir, "src");
|
||||
await fs.promises.mkdir(sourceRoot, { recursive: true });
|
||||
const tempDir = path.join(tmpDir, "temp");
|
||||
await fs.promises.mkdir(tempDir, { recursive: true });
|
||||
const [dbLocation, sourceRoot, tempDir] = ["db", "src", "temp"].map((d) =>
|
||||
path.join(tmpDir, d),
|
||||
);
|
||||
await Promise.all(
|
||||
[dbLocation, sourceRoot, tempDir].map((d) =>
|
||||
fs.promises.mkdir(d, { recursive: true }),
|
||||
),
|
||||
);
|
||||
|
||||
const logger = getRunnerLogger(true);
|
||||
const config = createTestConfig({ dbLocation });
|
||||
@@ -73,6 +75,9 @@ test.serial(
|
||||
const getTempDirStub = sinon
|
||||
.stub(actionsUtil, "getTemporaryDirectory")
|
||||
.returns(tempDir);
|
||||
const getGitRootStub = sinon
|
||||
.stub(gitUtils, "getGitRoot")
|
||||
.resolves(sourceRoot);
|
||||
const changesFilePath = await writeOverlayChangesFile(
|
||||
config,
|
||||
sourceRoot,
|
||||
@@ -80,6 +85,7 @@ test.serial(
|
||||
);
|
||||
getFileOidsStubForOverlay.restore();
|
||||
getTempDirStub.restore();
|
||||
getGitRootStub.restore();
|
||||
|
||||
const fileContent = await fs.promises.readFile(changesFilePath, "utf-8");
|
||||
const parsedContent = JSON.parse(fileContent) as { changes: string[] };
|
||||
@@ -93,6 +99,232 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"writeOverlayChangesFile merges additional diff files into overlay changes",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
const [dbLocation, sourceRoot, tempDir] = ["db", "src", "temp"].map((d) =>
|
||||
path.join(tmpDir, d),
|
||||
);
|
||||
await Promise.all(
|
||||
[dbLocation, sourceRoot, tempDir].map((d) =>
|
||||
fs.promises.mkdir(d, { recursive: true }),
|
||||
),
|
||||
);
|
||||
|
||||
const logger = getRunnerLogger(true);
|
||||
const config = createTestConfig({ dbLocation });
|
||||
|
||||
// Mock the getFileOidsUnderPath function to return base OIDs
|
||||
// "reverted.js" has the same OID in both base and current, simulating
|
||||
// a revert PR where the file content matches the overlay-base
|
||||
const baseOids = {
|
||||
"unchanged.js": "aaa111",
|
||||
"modified.js": "bbb222",
|
||||
"reverted.js": "eee555",
|
||||
};
|
||||
const getFileOidsStubForBase = sinon
|
||||
.stub(gitUtils, "getFileOidsUnderPath")
|
||||
.resolves(baseOids);
|
||||
|
||||
// Write the base database OIDs file
|
||||
await writeBaseDatabaseOidsFile(config, sourceRoot);
|
||||
getFileOidsStubForBase.restore();
|
||||
|
||||
// Mock the getFileOidsUnderPath function to return overlay OIDs
|
||||
// "reverted.js" has the same OID as the base -- OID comparison alone
|
||||
// would NOT include it, only additionalChangedFiles causes it to appear
|
||||
const currentOids = {
|
||||
"unchanged.js": "aaa111",
|
||||
"modified.js": "ddd444", // Changed OID
|
||||
"reverted.js": "eee555", // Same OID as base -- not detected by OID comparison
|
||||
};
|
||||
const getFileOidsStubForOverlay = sinon
|
||||
.stub(gitUtils, "getFileOidsUnderPath")
|
||||
.resolves(currentOids);
|
||||
|
||||
const getTempDirStub = sinon
|
||||
.stub(actionsUtil, "getTemporaryDirectory")
|
||||
.returns(tempDir);
|
||||
const getGitRootStub = sinon
|
||||
.stub(gitUtils, "getGitRoot")
|
||||
.resolves(sourceRoot);
|
||||
|
||||
// Write a pr-diff-range.json file with diff ranges including
|
||||
// "reverted.js" (unchanged OIDs) and "modified.js" (already in OID changes)
|
||||
await fs.promises.writeFile(
|
||||
path.join(tempDir, "pr-diff-range.json"),
|
||||
JSON.stringify([
|
||||
{ path: "reverted.js", startLine: 1, endLine: 10 },
|
||||
{ path: "modified.js", startLine: 1, endLine: 5 },
|
||||
{ path: "diff-only.js", startLine: 1, endLine: 3 },
|
||||
]),
|
||||
);
|
||||
|
||||
const changesFilePath = await writeOverlayChangesFile(
|
||||
config,
|
||||
sourceRoot,
|
||||
logger,
|
||||
);
|
||||
getFileOidsStubForOverlay.restore();
|
||||
getTempDirStub.restore();
|
||||
getGitRootStub.restore();
|
||||
|
||||
const fileContent = await fs.promises.readFile(changesFilePath, "utf-8");
|
||||
const parsedContent = JSON.parse(fileContent) as { changes: string[] };
|
||||
|
||||
t.deepEqual(
|
||||
parsedContent.changes.sort(),
|
||||
["diff-only.js", "modified.js", "reverted.js"],
|
||||
"Should include OID-changed files, diff-only files, and deduplicate overlapping files",
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"writeOverlayChangesFile works without additional diff files",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
const [dbLocation, sourceRoot, tempDir] = ["db", "src", "temp"].map((d) =>
|
||||
path.join(tmpDir, d),
|
||||
);
|
||||
await Promise.all(
|
||||
[dbLocation, sourceRoot, tempDir].map((d) =>
|
||||
fs.promises.mkdir(d, { recursive: true }),
|
||||
),
|
||||
);
|
||||
|
||||
const logger = getRunnerLogger(true);
|
||||
const config = createTestConfig({ dbLocation });
|
||||
|
||||
// Mock the getFileOidsUnderPath function to return base OIDs
|
||||
const baseOids = {
|
||||
"unchanged.js": "aaa111",
|
||||
"modified.js": "bbb222",
|
||||
};
|
||||
const getFileOidsStubForBase = sinon
|
||||
.stub(gitUtils, "getFileOidsUnderPath")
|
||||
.resolves(baseOids);
|
||||
|
||||
await writeBaseDatabaseOidsFile(config, sourceRoot);
|
||||
getFileOidsStubForBase.restore();
|
||||
|
||||
const currentOids = {
|
||||
"unchanged.js": "aaa111",
|
||||
"modified.js": "ddd444",
|
||||
};
|
||||
const getFileOidsStubForOverlay = sinon
|
||||
.stub(gitUtils, "getFileOidsUnderPath")
|
||||
.resolves(currentOids);
|
||||
|
||||
const getTempDirStub = sinon
|
||||
.stub(actionsUtil, "getTemporaryDirectory")
|
||||
.returns(tempDir);
|
||||
const getGitRootStub = sinon
|
||||
.stub(gitUtils, "getGitRoot")
|
||||
.resolves(sourceRoot);
|
||||
|
||||
// No pr-diff-range.json file exists - should work the same as before
|
||||
const changesFilePath = await writeOverlayChangesFile(
|
||||
config,
|
||||
sourceRoot,
|
||||
logger,
|
||||
);
|
||||
getFileOidsStubForOverlay.restore();
|
||||
getTempDirStub.restore();
|
||||
getGitRootStub.restore();
|
||||
|
||||
const fileContent = await fs.promises.readFile(changesFilePath, "utf-8");
|
||||
const parsedContent = JSON.parse(fileContent) as { changes: string[] };
|
||||
|
||||
t.deepEqual(
|
||||
parsedContent.changes.sort(),
|
||||
["modified.js"],
|
||||
"Should only include OID-changed files when no additional files provided",
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"writeOverlayChangesFile converts diff range paths to sourceRoot-relative when sourceRoot is a subdirectory",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
// Simulate: repo root = tmpDir, sourceRoot = tmpDir/src
|
||||
const repoRoot = tmpDir;
|
||||
const sourceRoot = path.join(tmpDir, "src");
|
||||
const [dbLocation, tempDir] = ["db", "temp"].map((d) =>
|
||||
path.join(tmpDir, d),
|
||||
);
|
||||
await Promise.all(
|
||||
[dbLocation, sourceRoot, tempDir].map((d) =>
|
||||
fs.promises.mkdir(d, { recursive: true }),
|
||||
),
|
||||
);
|
||||
|
||||
const logger = getRunnerLogger(true);
|
||||
const config = createTestConfig({ dbLocation });
|
||||
|
||||
// Base OIDs (sourceRoot-relative paths)
|
||||
const baseOids = {
|
||||
"app.js": "aaa111",
|
||||
"lib/util.js": "bbb222",
|
||||
};
|
||||
const getFileOidsStubForBase = sinon
|
||||
.stub(gitUtils, "getFileOidsUnderPath")
|
||||
.resolves(baseOids);
|
||||
await writeBaseDatabaseOidsFile(config, sourceRoot);
|
||||
getFileOidsStubForBase.restore();
|
||||
|
||||
// Current OIDs — same as base (no OID changes)
|
||||
const currentOids = {
|
||||
"app.js": "aaa111",
|
||||
"lib/util.js": "bbb222",
|
||||
};
|
||||
const getFileOidsStubForOverlay = sinon
|
||||
.stub(gitUtils, "getFileOidsUnderPath")
|
||||
.resolves(currentOids);
|
||||
|
||||
const getTempDirStub = sinon
|
||||
.stub(actionsUtil, "getTemporaryDirectory")
|
||||
.returns(tempDir);
|
||||
// getGitRoot returns the repo root (parent of sourceRoot)
|
||||
const getGitRootStub = sinon
|
||||
.stub(gitUtils, "getGitRoot")
|
||||
.resolves(repoRoot);
|
||||
|
||||
// Diff ranges use repo-root-relative paths (as returned by the GitHub compare API)
|
||||
await fs.promises.writeFile(
|
||||
path.join(tempDir, "pr-diff-range.json"),
|
||||
JSON.stringify([
|
||||
{ path: "src/app.js", startLine: 1, endLine: 10 },
|
||||
{ path: "src/lib/util.js", startLine: 5, endLine: 8 },
|
||||
{ path: "other/outside.js", startLine: 1, endLine: 3 }, // not under sourceRoot
|
||||
]),
|
||||
);
|
||||
|
||||
const changesFilePath = await writeOverlayChangesFile(
|
||||
config,
|
||||
sourceRoot,
|
||||
logger,
|
||||
);
|
||||
getFileOidsStubForOverlay.restore();
|
||||
getTempDirStub.restore();
|
||||
getGitRootStub.restore();
|
||||
|
||||
const fileContent = await fs.promises.readFile(changesFilePath, "utf-8");
|
||||
const parsedContent = JSON.parse(fileContent) as { changes: string[] };
|
||||
|
||||
t.deepEqual(
|
||||
parsedContent.changes.sort(),
|
||||
["app.js", "lib/util.js"],
|
||||
"Should convert repo-root-relative paths to sourceRoot-relative and filter out files outside sourceRoot",
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
interface DownloadOverlayBaseDatabaseTestCase {
|
||||
overlayDatabaseMode: OverlayDatabaseMode;
|
||||
useOverlayDatabaseCaching: boolean;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { getAutomationID } from "../api-client";
|
||||
import { createCacheKeyHash } from "../caching-utils";
|
||||
import { type CodeQL } from "../codeql";
|
||||
import { type Config } from "../config-utils";
|
||||
import { getCommitOid, getFileOidsUnderPath } from "../git-utils";
|
||||
import { getCommitOid, getFileOidsUnderPath, getGitRoot } from "../git-utils";
|
||||
import { Logger, withGroupAsync } from "../logging";
|
||||
import {
|
||||
CleanupLevel,
|
||||
@@ -130,11 +130,17 @@ export async function writeOverlayChangesFile(
|
||||
): Promise<string> {
|
||||
const baseFileOids = await readBaseDatabaseOidsFile(config, logger);
|
||||
const overlayFileOids = await getFileOidsUnderPath(sourceRoot);
|
||||
const changedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids);
|
||||
logger.info(
|
||||
`Found ${changedFiles.length} changed file(s) under ${sourceRoot}.`,
|
||||
`Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.`,
|
||||
);
|
||||
|
||||
// Merge in any file paths from precomputed PR diff ranges to ensure the
|
||||
// overlay always includes all files from the PR diff, even in edge cases
|
||||
// like revert PRs where OID comparison shows no change.
|
||||
const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger);
|
||||
const changedFiles = [...new Set([...oidChangedFiles, ...diffRangeFiles])];
|
||||
|
||||
const changedFilesJson = JSON.stringify({ changes: changedFiles });
|
||||
const overlayChangesFile = path.join(
|
||||
getTemporaryDirectory(),
|
||||
@@ -165,6 +171,65 @@ function computeChangedFiles(
|
||||
return changes;
|
||||
}
|
||||
|
||||
async function getDiffRangeFilePaths(
|
||||
sourceRoot: string,
|
||||
logger: Logger,
|
||||
): Promise<string[]> {
|
||||
const jsonFilePath = path.join(getTemporaryDirectory(), "pr-diff-range.json");
|
||||
if (!fs.existsSync(jsonFilePath)) {
|
||||
return [];
|
||||
}
|
||||
let diffRanges: Array<{ path: string }>;
|
||||
try {
|
||||
diffRanges = JSON.parse(fs.readFileSync(jsonFilePath, "utf8")) as Array<{
|
||||
path: string;
|
||||
}>;
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}`,
|
||||
);
|
||||
return [];
|
||||
}
|
||||
logger.debug(
|
||||
`Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.`,
|
||||
);
|
||||
const repoRelativePaths = [...new Set(diffRanges.map((r) => r.path))];
|
||||
|
||||
// Diff-range paths are relative to the repo root (from the GitHub compare
|
||||
// API), but overlay changed files must be relative to sourceRoot (to match
|
||||
// getFileOidsUnderPath output). Convert and filter accordingly.
|
||||
const repoRoot = await getGitRoot(sourceRoot);
|
||||
if (repoRoot === undefined) {
|
||||
logger.warning(
|
||||
"Cannot determine git root; returning diff range paths as-is.",
|
||||
);
|
||||
return repoRelativePaths;
|
||||
}
|
||||
|
||||
// e.g. if repoRoot=/workspace and sourceRoot=/workspace/src, prefix="src"
|
||||
const sourceRootRelPrefix = path
|
||||
.relative(repoRoot, sourceRoot)
|
||||
.replaceAll(path.sep, "/");
|
||||
|
||||
// If sourceRoot IS the repo root, prefix is "" and all paths pass through.
|
||||
if (sourceRootRelPrefix === "") {
|
||||
return repoRelativePaths;
|
||||
}
|
||||
|
||||
const prefixWithSlash = `${sourceRootRelPrefix}/`;
|
||||
const result: string[] = [];
|
||||
for (const p of repoRelativePaths) {
|
||||
if (p.startsWith(prefixWithSlash)) {
|
||||
result.push(p.slice(prefixWithSlash.length));
|
||||
} else {
|
||||
logger.debug(
|
||||
`Skipping diff range path "${p}" (not under source root "${sourceRootRelPrefix}").`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Constants for database caching
|
||||
const CACHE_VERSION = 1;
|
||||
const CACHE_PREFIX = "codeql-overlay-base-database";
|
||||
|
||||
Reference in New Issue
Block a user