Skip overlay analysis based on cached status

This commit is contained in:
Henry Mercer
2026-02-17 13:38:00 +00:00
parent e275d63e1d
commit ebad062f08
15 changed files with 635 additions and 456 deletions
+37
View File
@@ -19,6 +19,7 @@ import { GitVersionInfo } from "./git-utils";
import { KnownLanguage, Language } from "./languages";
import { getRunnerLogger } from "./logging";
import { CODEQL_OVERLAY_MINIMUM_VERSION, OverlayDatabaseMode } from "./overlay";
import * as overlayStatus from "./overlay/status";
import { parseRepositoryNwo } from "./repository";
import {
setupTests,
@@ -981,6 +982,7 @@ interface OverlayDatabaseModeTestSetup {
codeScanningConfig: configUtils.UserConfig;
diskUsage: DiskUsage | undefined;
memoryFlagValue: number;
shouldSkipOverlayAnalysisDueToCachedStatus: boolean;
}
const defaultOverlayDatabaseModeTestSetup: OverlayDatabaseModeTestSetup = {
@@ -1002,6 +1004,7 @@ const defaultOverlayDatabaseModeTestSetup: OverlayDatabaseModeTestSetup = {
numTotalBytes: 100_000_000_000,
},
memoryFlagValue: 6920,
shouldSkipOverlayAnalysisDueToCachedStatus: false,
};
const getOverlayDatabaseModeMacro = test.macro({
@@ -1036,6 +1039,10 @@ const getOverlayDatabaseModeMacro = test.macro({
sinon.stub(util, "checkDiskUsage").resolves(setup.diskUsage);
sinon
.stub(overlayStatus, "shouldSkipOverlayAnalysis")
.resolves(setup.shouldSkipOverlayAnalysisDueToCachedStatus);
// Mock feature flags
const features = createFeatures(setup.features);
@@ -1295,6 +1302,36 @@ test(
},
);
test(
getOverlayDatabaseModeMacro,
"No overlay-base database on default branch when cached status indicates previous failure",
{
languages: [KnownLanguage.javascript],
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
isDefaultBranch: true,
shouldSkipOverlayAnalysisDueToCachedStatus: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
},
);
test(
getOverlayDatabaseModeMacro,
"No overlay analysis on PR when cached status indicates previous failure",
{
languages: [KnownLanguage.javascript],
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
isPullRequest: true,
shouldSkipOverlayAnalysisDueToCachedStatus: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
},
);
test(
getOverlayDatabaseModeMacro,
"No overlay-base database on default branch when code-scanning feature enabled with disable-default-queries",
+16 -2
View File
@@ -45,6 +45,7 @@ import {
import { KnownLanguage, Language } from "./languages";
import { Logger } from "./logging";
import { CODEQL_OVERLAY_MINIMUM_VERSION, OverlayDatabaseMode } from "./overlay";
import { shouldSkipOverlayAnalysis } from "./overlay/status";
import { RepositoryNwo } from "./repository";
import { ToolsFeature } from "./tools-features";
import { downloadTrapCaches } from "./trap-caching";
@@ -60,6 +61,7 @@ import {
getErrorMessage,
isInTestMode,
joinAtMost,
DiskUsage,
} from "./util";
export * from "./config/db-config";
@@ -672,10 +674,10 @@ async function isOverlayAnalysisFeatureEnabled(
* and the maximum memory CodeQL will be allowed to use.
*/
async function runnerSupportsOverlayAnalysis(
diskUsage: DiskUsage | undefined,
ramInput: string | undefined,
logger: Logger,
): Promise<boolean> {
const diskUsage = await checkDiskUsage(logger);
if (
diskUsage === undefined ||
diskUsage.numAvailableBytes < OVERLAY_MINIMUM_AVAILABLE_DISK_SPACE_BYTES
@@ -762,13 +764,25 @@ export async function getOverlayDatabaseMode(
codeScanningConfig,
)
) {
const diskUsage = await checkDiskUsage(logger);
const performResourceChecks = !(await features.getValue(
Feature.OverlayAnalysisSkipResourceChecks,
codeql,
));
if (
diskUsage &&
(await shouldSkipOverlayAnalysis(codeql, languages, diskUsage, logger))
) {
logger.info(
`Setting overlay database mode to ${OverlayDatabaseMode.None} ` +
"because overlay analysis previously failed with this combination of languages, " +
"disk space, and CodeQL version. " +
"Consider running CodeQL analysis on a larger runner.",
);
overlayDatabaseMode = OverlayDatabaseMode.None;
} else if (
performResourceChecks &&
!(await runnerSupportsOverlayAnalysis(ramInput, logger))
!(await runnerSupportsOverlayAnalysis(diskUsage, ramInput, logger))
) {
overlayDatabaseMode = OverlayDatabaseMode.None;
} else if (isAnalyzingPullRequest()) {
+30 -4
View File
@@ -34,6 +34,32 @@ export interface OverlayStatus {
builtOverlayBaseDatabase: boolean;
}
/**
* Whether overlay analysis should be skipped, based on the cached status for the given languages and disk usage.
*/
export async function shouldSkipOverlayAnalysis(
codeql: CodeQL,
languages: string[],
diskUsage: DiskUsage,
logger: Logger,
): Promise<boolean> {
const status = await getOverlayStatus(codeql, languages, diskUsage, logger);
if (status === undefined) {
logger.debug("No cached overlay status found.");
return false;
}
if (!status.builtOverlayBaseDatabase) {
logger.info(
"Cached overlay status indicates that building an overlay base database was unsuccessful, so will skip overlay analysis.",
);
return true;
}
logger.debug(
"Cached overlay status indicates that building an overlay base database was successful.",
);
return false;
}
/**
* Retrieve overlay status from the Actions cache, if available.
*
@@ -60,17 +86,17 @@ export async function getOverlayStatus(
MAX_CACHE_OPERATION_MS,
actionsCache.restoreCache([statusFile], cacheKey),
() => {
logger.info("Timed out restoring overlay status from cache");
logger.info("Timed out restoring overlay status from cache.");
},
);
if (foundKey === undefined) {
logger.debug("No overlay status found in Actions cache");
logger.debug("No overlay status found in Actions cache.");
return undefined;
}
if (!fs.existsSync(statusFile)) {
logger.debug(
"Overlay status cache entry found but status file is missing",
"Overlay status cache entry found but status file is missing.",
);
return undefined;
}
@@ -114,7 +140,7 @@ export async function saveOverlayStatus(
() => {},
);
if (cacheId === undefined) {
logger.warning("Timed out saving overlay status to cache");
logger.warning("Timed out saving overlay status to cache.");
return false;
}
logger.info(`Saved overlay status to Actions cache with key ${cacheKey}`);