mirror of
https://github.com/github/codeql-action.git
synced 2026-04-29 18:30:14 +00:00
refactor: fall back to non-overlay analysis when diff-informed analysis is unavailable
This commit is contained in:
Generated
+59
-37
@@ -106110,9 +106110,6 @@ function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) {
|
||||
}
|
||||
|
||||
// src/diff-informed-analysis-utils.ts
|
||||
async function shouldPerformDiffInformedAnalysis(codeql, features, logger) {
|
||||
return await getDiffInformedAnalysisBranches(codeql, features, logger) !== void 0;
|
||||
}
|
||||
async function getDiffInformedAnalysisBranches(codeql, features, logger) {
|
||||
if (!await features.getValue("diff_informed_queries" /* DiffInformedQueries */, codeql)) {
|
||||
return void 0;
|
||||
@@ -106129,6 +106126,37 @@ async function getDiffInformedAnalysisBranches(codeql, features, logger) {
|
||||
}
|
||||
return branches;
|
||||
}
|
||||
async function prepareDiffInformedAnalysis(codeql, features, logger) {
|
||||
try {
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger
|
||||
);
|
||||
if (!branches) {
|
||||
return { shouldRun: false, isAvailable: false };
|
||||
}
|
||||
const isAvailable = await withGroupAsync(
|
||||
"Computing PR diff ranges",
|
||||
async () => {
|
||||
try {
|
||||
return await computeAndPersistDiffRanges(branches, logger);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to compute diff-informed analysis ranges: ${getErrorMessage(e)}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
return { shouldRun: true, isAvailable };
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to determine diff-informed analysis availability: ${getErrorMessage(e)}`
|
||||
);
|
||||
return { shouldRun: true, isAvailable: false };
|
||||
}
|
||||
}
|
||||
function writeDiffRangesJsonFile(logger, ranges) {
|
||||
const jsonContents = JSON.stringify(ranges, null, 2);
|
||||
const jsonFilePath = getDiffRangesJsonFilePath();
|
||||
@@ -106159,6 +106187,18 @@ async function getPullRequestEditedDiffRanges(branches, logger) {
|
||||
}
|
||||
return results;
|
||||
}
|
||||
async function computeAndPersistDiffRanges(branches, logger) {
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === void 0) {
|
||||
return false;
|
||||
}
|
||||
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).`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
async function getFileDiffsWithBasehead(branches, logger) {
|
||||
const repositoryNwo = getRepositoryNwoFromEnv(
|
||||
"CODE_SCANNING_REPOSITORY",
|
||||
@@ -106974,6 +107014,19 @@ function userConfigFromActionPath(tempDir) {
|
||||
function hasQueryCustomisation(userConfig) {
|
||||
return isDefined2(userConfig["disable-default-queries"]) || isDefined2(userConfig.queries) || isDefined2(userConfig["query-filters"]);
|
||||
}
|
||||
function applyIncrementalAnalysisSettings(config, diffInformedAnalysis, logger) {
|
||||
if (config.overlayDatabaseMode === "overlay" /* Overlay */ && diffInformedAnalysis.shouldRun && !diffInformedAnalysis.isAvailable) {
|
||||
logger.warning(
|
||||
`Diff-informed analysis is not available for this pull request. Reverting overlay database mode to ${"none" /* None */}.`
|
||||
);
|
||||
config.overlayDatabaseMode = "none" /* None */;
|
||||
}
|
||||
if (config.overlayDatabaseMode === "overlay" /* Overlay */ || diffInformedAnalysis.isAvailable) {
|
||||
config.extraQueryExclusions.push({
|
||||
exclude: { tags: "exclude-from-incremental" }
|
||||
});
|
||||
}
|
||||
}
|
||||
async function initConfig(features, inputs) {
|
||||
const { logger, tempDir } = inputs;
|
||||
if (inputs.configInput) {
|
||||
@@ -107083,15 +107136,12 @@ async function initConfig(features, inputs) {
|
||||
overlayDisabledReason
|
||||
);
|
||||
}
|
||||
if (config.overlayDatabaseMode === "overlay" /* Overlay */ || await shouldPerformDiffInformedAnalysis(
|
||||
const diffInformedAnalysis = await prepareDiffInformedAnalysis(
|
||||
inputs.codeql,
|
||||
inputs.features,
|
||||
logger
|
||||
)) {
|
||||
config.extraQueryExclusions.push({
|
||||
exclude: { tags: "exclude-from-incremental" }
|
||||
});
|
||||
}
|
||||
);
|
||||
applyIncrementalAnalysisSettings(config, diffInformedAnalysis, logger);
|
||||
if (await isTrapCachingEnabled(features, config.overlayDatabaseMode)) {
|
||||
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(
|
||||
inputs.codeql,
|
||||
@@ -110359,7 +110409,6 @@ async function run(startedAt) {
|
||||
logFileCoverageOnPrsDeprecationWarning(logger);
|
||||
}
|
||||
await checkInstallPython311(config.languages, codeql);
|
||||
await computeAndPersistDiffRanges(codeql, features, logger);
|
||||
} catch (unwrappedError) {
|
||||
const error3 = wrapError(unwrappedError);
|
||||
core15.setFailed(error3.message);
|
||||
@@ -110627,33 +110676,6 @@ async function loadRepositoryProperties(repositoryNwo, logger) {
|
||||
return new Failure(error3);
|
||||
}
|
||||
}
|
||||
async function computeAndPersistDiffRanges(codeql, features, logger) {
|
||||
await withGroupAsync("Computing PR diff ranges", async () => {
|
||||
try {
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger
|
||||
);
|
||||
if (!branches) {
|
||||
return;
|
||||
}
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === void 0) {
|
||||
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, zstdAvailability) {
|
||||
addNoLanguageDiagnostic(
|
||||
config,
|
||||
|
||||
@@ -2200,3 +2200,80 @@ test.serial(
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"applyIncrementalAnalysisSettings: no-op when mode is not Overlay and diff-informed is unavailable",
|
||||
(t) => {
|
||||
const config = createTestConfig({});
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
{ shouldRun: false, isAvailable: false },
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.deepEqual(config.extraQueryExclusions, []);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"applyIncrementalAnalysisSettings: keeps overlay mode and adds exclusions when diff-informed analysis is disabled",
|
||||
(t) => {
|
||||
const config = createTestConfig({});
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.Overlay;
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
{ shouldRun: false, isAvailable: false },
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.Overlay);
|
||||
t.deepEqual(config.extraQueryExclusions, [
|
||||
{ exclude: { tags: "exclude-from-incremental" } },
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"applyIncrementalAnalysisSettings: reverts to None without exclusions when diff-informed analysis is unavailable",
|
||||
(t) => {
|
||||
const config = createTestConfig({});
|
||||
config.overlayDatabaseMode =
|
||||
OverlayDatabaseMode.Overlay as OverlayDatabaseMode;
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
{ shouldRun: true, isAvailable: false },
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.deepEqual(config.extraQueryExclusions, []);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"applyIncrementalAnalysisSettings: adds exclusions for diff-informed-only runs",
|
||||
(t) => {
|
||||
const config = createTestConfig({});
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
{ shouldRun: true, isAvailable: true },
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.deepEqual(config.extraQueryExclusions, [
|
||||
{ exclude: { tags: "exclude-from-incremental" } },
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
+47
-13
@@ -31,7 +31,10 @@ import {
|
||||
addNoLanguageDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import { shouldPerformDiffInformedAnalysis } from "./diff-informed-analysis-utils";
|
||||
import {
|
||||
type DiffInformedAnalysisPreparation,
|
||||
prepareDiffInformedAnalysis,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import * as errorMessages from "./error-messages";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
@@ -1076,6 +1079,42 @@ function hasQueryCustomisation(userConfig: UserConfig): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the incremental-analysis configuration for this run.
|
||||
*
|
||||
* If overlay mode was selected for a PR but diff-informed analysis should have
|
||||
* run and could not be prepared, fall back to a full non-overlay analysis.
|
||||
* Query exclusions for incremental-only queries are applied only when the final
|
||||
* configuration still uses overlay analysis or diff-informed analysis is
|
||||
* actually available.
|
||||
*/
|
||||
export function applyIncrementalAnalysisSettings(
|
||||
config: Config,
|
||||
diffInformedAnalysis: DiffInformedAnalysisPreparation,
|
||||
logger: Logger,
|
||||
): void {
|
||||
if (
|
||||
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay &&
|
||||
diffInformedAnalysis.shouldRun &&
|
||||
!diffInformedAnalysis.isAvailable
|
||||
) {
|
||||
logger.warning(
|
||||
"Diff-informed analysis is not available for this pull request. " +
|
||||
`Reverting overlay database mode to ${OverlayDatabaseMode.None}.`,
|
||||
);
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
}
|
||||
|
||||
if (
|
||||
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay ||
|
||||
diffInformedAnalysis.isAvailable
|
||||
) {
|
||||
config.extraQueryExclusions.push({
|
||||
exclude: { tags: "exclude-from-incremental" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and return the config.
|
||||
*
|
||||
@@ -1230,18 +1269,13 @@ export async function initConfig(
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay ||
|
||||
(await shouldPerformDiffInformedAnalysis(
|
||||
inputs.codeql,
|
||||
inputs.features,
|
||||
logger,
|
||||
))
|
||||
) {
|
||||
config.extraQueryExclusions.push({
|
||||
exclude: { tags: "exclude-from-incremental" },
|
||||
});
|
||||
}
|
||||
const diffInformedAnalysis = await prepareDiffInformedAnalysis(
|
||||
inputs.codeql,
|
||||
inputs.features,
|
||||
logger,
|
||||
);
|
||||
|
||||
applyIncrementalAnalysisSettings(config, diffInformedAnalysis, logger);
|
||||
|
||||
if (await isTrapCachingEnabled(features, config.overlayDatabaseMode)) {
|
||||
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(
|
||||
|
||||
@@ -5,9 +5,9 @@ import type { PullRequestBranches } from "./actions-util";
|
||||
import { getApiClient, getGitHubVersion } from "./api-client";
|
||||
import type { CodeQL } from "./codeql";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
import { Logger } from "./logging";
|
||||
import { Logger, withGroupAsync } from "./logging";
|
||||
import { getRepositoryNwoFromEnv } from "./repository";
|
||||
import { GitHubVariant, satisfiesGHESVersion } from "./util";
|
||||
import { getErrorMessage, GitHubVariant, satisfiesGHESVersion } from "./util";
|
||||
|
||||
/**
|
||||
* This interface is an abbreviated version of the file diff object returned by
|
||||
@@ -69,6 +69,61 @@ export async function getDiffInformedAnalysisBranches(
|
||||
return branches;
|
||||
}
|
||||
|
||||
export interface DiffInformedAnalysisPreparation {
|
||||
/**
|
||||
* Whether diff-informed analysis applies to this workflow run.
|
||||
*/
|
||||
shouldRun: boolean;
|
||||
/**
|
||||
* Whether the diff ranges were successfully prepared and can be used.
|
||||
*/
|
||||
isAvailable: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the diff ranges needed for diff-informed analysis for the current
|
||||
* run.
|
||||
*
|
||||
* @returns Whether diff-informed analysis applies to this run, and whether it
|
||||
* was successfully prepared for use.
|
||||
*/
|
||||
export async function prepareDiffInformedAnalysis(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<DiffInformedAnalysisPreparation> {
|
||||
try {
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
if (!branches) {
|
||||
return { shouldRun: false, isAvailable: false };
|
||||
}
|
||||
|
||||
const isAvailable = await withGroupAsync(
|
||||
"Computing PR diff ranges",
|
||||
async () => {
|
||||
try {
|
||||
return await computeAndPersistDiffRanges(branches, logger);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to compute diff-informed analysis ranges: ${getErrorMessage(e)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
return { shouldRun: true, isAvailable };
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to determine diff-informed analysis availability: ${getErrorMessage(e)}`,
|
||||
);
|
||||
return { shouldRun: true, isAvailable: false };
|
||||
}
|
||||
}
|
||||
|
||||
export interface DiffThunkRange {
|
||||
/** Relative path from the repository root, using forward slashes as separators. */
|
||||
path: string;
|
||||
@@ -151,6 +206,33 @@ export async function getPullRequestEditedDiffRanges(
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and persist the diff ranges for a pull request. This fetches the
|
||||
* diff from the GitHub API and writes it to the diff ranges JSON file so that
|
||||
* CodeQL can use it for diff-informed analysis.
|
||||
*
|
||||
* @param branches The base and head branches of the pull request, as returned
|
||||
* by `getDiffInformedAnalysisBranches`.
|
||||
* @param logger
|
||||
* @returns `true` if the diff ranges were successfully computed and persisted,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
export async function computeAndPersistDiffRanges(
|
||||
branches: PullRequestBranches,
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === undefined) {
|
||||
return false;
|
||||
}
|
||||
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).`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function getFileDiffsWithBasehead(
|
||||
branches: PullRequestBranches,
|
||||
logger: Logger,
|
||||
|
||||
+1
-43
@@ -37,11 +37,6 @@ 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 {
|
||||
@@ -59,7 +54,7 @@ import {
|
||||
runDatabaseInitCluster,
|
||||
} from "./init";
|
||||
import { JavaEnvVars, KnownLanguage } from "./languages";
|
||||
import { getActionsLogger, Logger, withGroupAsync } from "./logging";
|
||||
import { getActionsLogger, Logger } from "./logging";
|
||||
import {
|
||||
downloadOverlayBaseDatabaseFromCache,
|
||||
OverlayBaseDatabaseDownloadStats,
|
||||
@@ -427,7 +422,6 @@ 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);
|
||||
@@ -818,42 +812,6 @@ 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> {
|
||||
await withGroupAsync("Computing PR diff ranges", async () => {
|
||||
try {
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user