From 4c0acfe29e5029e945654d707e00c54ec87d0557 Mon Sep 17 00:00:00 2001 From: Alex Eyers-Taylor Date: Wed, 8 Oct 2025 17:57:03 +0100 Subject: [PATCH] Consume precomputed diff ranges in analyze and avoid getting them from the API. --- lib/analyze-action.js | 188 +++++------------------------------------- lib/init-action.js | 6 -- src/analyze-action.ts | 11 +-- src/analyze.ts | 37 ++++++--- 4 files changed, 45 insertions(+), 197 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index be30d1376..6981690e1 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -90112,29 +90112,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", @@ -91534,34 +91511,9 @@ var GitHubFeatureFlags = class { }; // 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 === 1 /* 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 path9.join(getTemporaryDirectory(), "pr-diff-range.json"); } -function writeDiffRangesJsonFile(logger, ranges) { - const jsonContents = JSON.stringify(ranges, null, 2); - const jsonFilePath = getDiffRangesJsonFilePath(); - fs8.writeFileSync(jsonFilePath, jsonContents); - logger.debug( - `Wrote pr-diff-range JSON file to ${jsonFilePath}: -${jsonContents}` - ); -} function readDiffRangesJsonFile(logger) { const jsonFilePath = getDiffRangesJsonFilePath(); if (!fs8.existsSync(jsonFilePath)) { @@ -91575,117 +91527,6 @@ ${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 - } - ); - logger.debug( - `Response from compareCommitsWithBasehead(${basehead}): -${JSON.stringify(response, null, 2)}` - ); - return response.data.files; - } catch (error2) { - if (error2.status) { - logger.warning(`Error retrieving diff ${basehead}: ${error2.message}`); - logger.debug( - `Error running compareCommitsWithBasehead(${basehead}): -Request: ${JSON.stringify(error2.request, null, 2)} -Error Response: ${JSON.stringify(error2.response, null, 2)}` - ); - return void 0; - } else { - throw error2; - } - } -} -function getDiffRanges(fileDiff, logger) { - const filename = path9.join(getRequiredInput("checkout_path"), fileDiff.filename).replaceAll(path9.sep, "/"); - if (fileDiff.patch === void 0) { - if (fileDiff.changes === 0) { - return []; - } - return [ - { - path: 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: 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/trap-caching.ts var actionsCache2 = __toESM(require_cache3()); @@ -93747,14 +93588,29 @@ async function finalizeDatabaseCreation(codeql, config, threadsFlag, memoryFlag, 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 () => { + let diffRanges; + try { + diffRanges = readDiffRangesJsonFile(logger); + } catch (e) { + logger.debug( + `Failed to read precomputed diff ranges: ${getErrorMessage(e)}` + ); + diffRanges = void 0; + } + if (diffRanges === void 0) { + logger.info( + "No precomputed diff ranges found; skipping diff-informed analysis stage." + ); + return void 0; + } + const fileCount = new Set(diffRanges.filter((r) => r.path).map((r) => r.path)).size; logger.info( - `Calculating diff ranges for ${branches.base}...${branches.head}` + `Using precomputed diff ranges (${diffRanges.length} ranges across ${fileCount} files).` ); - const diffRanges = await getPullRequestEditedDiffRanges(branches, logger); const packDir = writeDiffRangeDataExtensionPack(logger, diffRanges); if (packDir === void 0) { logger.warning( @@ -93817,7 +93673,6 @@ extensions: `Wrote pr-diff-range extension pack to ${extensionFilePath}: ${extensionContents}` ); - writeDiffRangesJsonFile(logger, ranges); return diffRangeDir; } var defaultSuites = /* @__PURE__ */ new Set([ @@ -96206,12 +96061,7 @@ async function run() { 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( diff --git a/lib/init-action.js b/lib/init-action.js index 24a459a5b..445977d38 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -91255,16 +91255,10 @@ async function computeAndPersistDiffRangesEarly(codeql, features, logger) { logger ); if (!branches) { - logger.debug( - "Diff-informed analysis not enabled (feature flag or context); skipping diff range computation." - ); return; } const ranges = await getPullRequestEditedDiffRanges(branches, logger); if (ranges === void 0) { - logger.info( - "Diff ranges unavailable (API limits, truncation, or error); will fall back to analyze-time computation." - ); return; } writeDiffRangesJsonFile(logger, ranges); diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 3d0fb1c89..864063af8 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -30,7 +30,6 @@ import { DependencyCacheUploadStatusReport, uploadDependencyCaches, } from "./dependency-caching"; -import { getDiffInformedAnalysisBranches } from "./diff-informed-analysis-utils"; import { EnvVar } from "./environment"; import { Feature, Features } from "./feature-flags"; import { KnownLanguage } from "./languages"; @@ -299,14 +298,8 @@ async function run() { 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); diff --git a/src/analyze.ts b/src/analyze.ts index b3dc31a65..a9daa8234 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -6,7 +6,7 @@ import * as io from "@actions/io"; import * as del from "del"; import * as yaml from "js-yaml"; -import { getTemporaryDirectory, PullRequestBranches } from "./actions-util"; +import { getTemporaryDirectory } from "./actions-util"; import * as analyses from "./analyses"; // (getApiClient import removed; no longer needed after diff refactor) import { setupCppAutobuild } from "./autobuild"; @@ -14,11 +14,7 @@ import { type CodeQL } from "./codeql"; import * as configUtils from "./config-utils"; import { getJavaTempDependencyDir } from "./dependency-caching"; import { addDiagnostic, makeDiagnostic } from "./diagnostics"; -import { - DiffThunkRange, - writeDiffRangesJsonFile, - getPullRequestEditedDiffRanges, -} from "./diff-informed-analysis-utils"; +import { DiffThunkRange, readDiffRangesJsonFile } from "./diff-informed-analysis-utils"; import { EnvVar } from "./environment"; import { FeatureEnablement, Feature } from "./feature-flags"; import { KnownLanguage, Language } from "./languages"; @@ -284,17 +280,35 @@ async function finalizeDatabaseCreation( * the diff range information, or `undefined` if the feature is disabled. */ export async function setupDiffInformedQueryRun( - branches: PullRequestBranches, logger: Logger, ): Promise { return await withGroupAsync( "Generating diff range extension pack", async () => { + // Only use precomputed diff ranges; never recompute here. + let diffRanges: DiffThunkRange[] | undefined; + try { + diffRanges = readDiffRangesJsonFile(logger); + } catch (e) { + logger.debug( + `Failed to read precomputed diff ranges: ${util.getErrorMessage(e)}`, + ); + diffRanges = undefined; + } + + if (diffRanges === undefined) { + logger.info( + "No precomputed diff ranges found; skipping diff-informed analysis stage.", + ); + return undefined; + } + + const fileCount = new Set(diffRanges.filter((r) => r.path).map((r) => r.path)).size; logger.info( - `Calculating diff ranges for ${branches.base}...${branches.head}`, + `Using precomputed diff ranges (${diffRanges.length} ranges across ${fileCount} files).`, ); - const diffRanges = await getPullRequestEditedDiffRanges(branches, logger); - const packDir = writeDiffRangeDataExtensionPack(logger, diffRanges); + + const packDir = writeDiffRangeDataExtensionPack(logger, diffRanges); if (packDir === undefined) { logger.warning( "Cannot create diff range extension pack for diff-informed queries; " + @@ -392,9 +406,6 @@ extensions: `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; }