From b371ccd8eaf4fcfcfaca930844c96de5b6469cb2 Mon Sep 17 00:00:00 2001 From: Henry Mercer Date: Wed, 4 Mar 2026 13:53:12 +0100 Subject: [PATCH] Refactor `getOverlayDatabaseMode` and add new disablement reason --- lib/init-action.js | 183 +++++++++++++++---------- src/config-utils.test.ts | 1 + src/config-utils.ts | 269 +++++++++++++++++++++++-------------- src/overlay/diagnostics.ts | 2 + 4 files changed, 278 insertions(+), 177 deletions(-) diff --git a/lib/init-action.js b/lib/init-action.js index c9ad04ec2..a86eaf676 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -106388,9 +106388,12 @@ var OVERLAY_ANALYSIS_CODE_SCANNING_FEATURES = { rust: "overlay_analysis_code_scanning_rust" /* OverlayAnalysisCodeScanningRust */, swift: "overlay_analysis_code_scanning_swift" /* OverlayAnalysisCodeScanningSwift */ }; -async function getOverlayFeatureDisabledReason(features, codeql, languages, codeScanningConfig) { +async function checkOverlayAnalysisFeatureEnabled(features, codeql, languages, codeScanningConfig) { if (!await features.getValue("overlay_analysis" /* OverlayAnalysis */, codeql)) { - return "overall-feature-not-enabled" /* OverallFeatureNotEnabled */; + return { + enabled: false, + reason: "overall-feature-not-enabled" /* OverallFeatureNotEnabled */ + }; } let enableForCodeScanningOnly = false; for (const language of languages) { @@ -106403,15 +106406,18 @@ async function getOverlayFeatureDisabledReason(features, codeql, languages, code enableForCodeScanningOnly = true; continue; } - return "language-not-enabled" /* LanguageNotEnabled */; + return { enabled: false, reason: "language-not-enabled" /* LanguageNotEnabled */ }; } if (enableForCodeScanningOnly) { const isCodeScanningOnly = codeScanningConfig["disable-default-queries"] !== true && codeScanningConfig.packs === void 0 && codeScanningConfig.queries === void 0 && codeScanningConfig["query-filters"] === void 0; if (!isCodeScanningOnly) { - return "non-default-queries" /* NonDefaultQueries */; + return { + enabled: false, + reason: "non-default-queries" /* NonDefaultQueries */ + }; } } - return void 0; + return { enabled: true }; } function runnerHasSufficientDiskSpace(diskUsage, logger, useV2ResourceChecks) { const minimumDiskSpaceBytes = useV2ResourceChecks ? OVERLAY_MINIMUM_AVAILABLE_DISK_SPACE_V2_BYTES : OVERLAY_MINIMUM_AVAILABLE_DISK_SPACE_BYTES; @@ -106447,97 +106453,128 @@ async function runnerHasSufficientMemory(codeql, ramInput, logger) { ); return true; } -async function getResourceDisabledReason(codeql, diskUsage, ramInput, logger, useV2ResourceChecks) { - if (diskUsage === void 0) { - logger.info( - `Unable to determine available disk space for overlay analysis. Setting overlay database mode to ${"none" /* None */}.` - ); - return "unable-to-determine-disk-usage" /* UnableToDetermineDiskUsage */; - } +async function checkRunnerResources(codeql, diskUsage, ramInput, logger, useV2ResourceChecks) { if (!runnerHasSufficientDiskSpace(diskUsage, logger, useV2ResourceChecks)) { - return "insufficient-disk-space" /* InsufficientDiskSpace */; + return { + sufficient: false, + reason: "insufficient-disk-space" /* InsufficientDiskSpace */ + }; } if (!await runnerHasSufficientMemory(codeql, ramInput, logger)) { - return "insufficient-memory" /* InsufficientMemory */; + return { + sufficient: false, + reason: "insufficient-memory" /* InsufficientMemory */ + }; } - return void 0; + return { sufficient: true }; } async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, buildMode, ramInput, codeScanningConfig, repositoryProperties, gitVersion, logger) { - let overlayDatabaseMode = "none" /* None */; - let useOverlayDatabaseCaching = false; - let disabledReason; + const disabledResult = (reason) => ({ + overlayDatabaseMode: "none" /* None */, + useOverlayDatabaseCaching: false, + disabledReason: reason + }); const modeEnv = process.env.CODEQL_OVERLAY_DATABASE_MODE; if (modeEnv === "overlay" /* Overlay */ || modeEnv === "overlay-base" /* OverlayBase */ || modeEnv === "none" /* None */) { - overlayDatabaseMode = modeEnv; logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} from the CODEQL_OVERLAY_DATABASE_MODE environment variable.` + `Setting overlay database mode to ${modeEnv} from the CODEQL_OVERLAY_DATABASE_MODE environment variable.` ); - } else if (repositoryProperties["github-codeql-disable-overlay" /* DISABLE_OVERLAY */] === true) { + return validateOverlayDatabaseMode( + modeEnv, + false, + codeql, + languages, + sourceRoot, + buildMode, + gitVersion, + logger + ); + } + if (repositoryProperties["github-codeql-disable-overlay" /* DISABLE_OVERLAY */] === true) { logger.info( `Setting overlay database mode to ${"none" /* None */} because the ${"github-codeql-disable-overlay" /* DISABLE_OVERLAY */} repository property is set to true.` ); - overlayDatabaseMode = "none" /* None */; - disabledReason = "disabled-by-repository-property" /* DisabledByRepositoryProperty */; - } else if ((disabledReason = await getOverlayFeatureDisabledReason( + return disabledResult("disabled-by-repository-property" /* DisabledByRepositoryProperty */); + } + const featureResult = await checkOverlayAnalysisFeatureEnabled( features, codeql, languages, codeScanningConfig - )) === void 0) { - const performResourceChecks = !await features.getValue( - "overlay_analysis_skip_resource_checks" /* OverlayAnalysisSkipResourceChecks */, - codeql - ); - const useV2ResourceChecks = await features.getValue( - "overlay_analysis_resource_checks_v2" /* OverlayAnalysisResourceChecksV2 */ - ); - const checkOverlayStatus = await features.getValue( - "overlay_analysis_status_check" /* OverlayAnalysisStatusCheck */ - ); - const diskUsage = performResourceChecks || checkOverlayStatus ? await checkDiskUsage(logger) : void 0; - let resourceDisabledReason; - if (performResourceChecks && (resourceDisabledReason = await getResourceDisabledReason( - codeql, - diskUsage, - ramInput, - logger, - useV2ResourceChecks - )) !== void 0) { - overlayDatabaseMode = "none" /* None */; - disabledReason = resourceDisabledReason; - } else if (checkOverlayStatus && diskUsage === void 0) { - logger.warning( - `Unable to determine disk usage, therefore setting overlay database mode to ${"none" /* None */}.` - ); - overlayDatabaseMode = "none" /* None */; - disabledReason = "unable-to-determine-disk-usage" /* UnableToDetermineDiskUsage */; - } else if (checkOverlayStatus && diskUsage && await shouldSkipOverlayAnalysis(codeql, languages, diskUsage, logger)) { - logger.info( - `Setting overlay database mode to ${"none" /* None */} because overlay analysis previously failed with this combination of languages, disk space, and CodeQL version.` - ); - overlayDatabaseMode = "none" /* None */; - disabledReason = "skipped-due-to-cached-status" /* SkippedDueToCachedStatus */; - } else if (isAnalyzingPullRequest()) { - overlayDatabaseMode = "overlay" /* Overlay */; - useOverlayDatabaseCaching = true; - logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing a pull request.` - ); - } else if (await isAnalyzingDefaultBranch()) { - overlayDatabaseMode = "overlay-base" /* OverlayBase */; - useOverlayDatabaseCaching = true; - logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing the default branch.` - ); - } + ); + if (!featureResult.enabled) { + return disabledResult(featureResult.reason); } + const performResourceChecks = !await features.getValue( + "overlay_analysis_skip_resource_checks" /* OverlayAnalysisSkipResourceChecks */, + codeql + ); + const useV2ResourceChecks = await features.getValue( + "overlay_analysis_resource_checks_v2" /* OverlayAnalysisResourceChecksV2 */ + ); + const checkOverlayStatus = await features.getValue( + "overlay_analysis_status_check" /* OverlayAnalysisStatusCheck */ + ); + const diskUsage = performResourceChecks || checkOverlayStatus ? await checkDiskUsage(logger) : void 0; + if ((performResourceChecks || checkOverlayStatus) && diskUsage === void 0) { + logger.warning( + `Unable to determine disk usage, therefore setting overlay database mode to ${"none" /* None */}.` + ); + return disabledResult("unable-to-determine-disk-usage" /* UnableToDetermineDiskUsage */); + } + const resourceResult = performResourceChecks && diskUsage ? await checkRunnerResources( + codeql, + diskUsage, + ramInput, + logger, + useV2ResourceChecks + ) : { sufficient: true }; + if (!resourceResult.sufficient) { + return disabledResult(resourceResult.reason); + } + if (checkOverlayStatus && diskUsage && await shouldSkipOverlayAnalysis(codeql, languages, diskUsage, logger)) { + logger.info( + `Setting overlay database mode to ${"none" /* None */} because overlay analysis previously failed with this combination of languages, disk space, and CodeQL version.` + ); + return disabledResult("skipped-due-to-cached-status" /* SkippedDueToCachedStatus */); + } + let overlayDatabaseMode; + if (isAnalyzingPullRequest()) { + overlayDatabaseMode = "overlay" /* Overlay */; + logger.info( + `Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing a pull request.` + ); + } else if (await isAnalyzingDefaultBranch()) { + overlayDatabaseMode = "overlay-base" /* OverlayBase */; + logger.info( + `Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing the default branch.` + ); + } else { + return disabledResult("not-pull-request-or-default-branch" /* NotPullRequestOrDefaultBranch */); + } + return validateOverlayDatabaseMode( + overlayDatabaseMode, + true, + codeql, + languages, + sourceRoot, + buildMode, + gitVersion, + logger + ); +} +async function validateOverlayDatabaseMode(overlayDatabaseMode, useOverlayDatabaseCaching, codeql, languages, sourceRoot, buildMode, gitVersion, logger) { const disabledResult = (reason) => ({ overlayDatabaseMode: "none" /* None */, useOverlayDatabaseCaching: false, disabledReason: reason }); if (overlayDatabaseMode === "none" /* None */) { - return disabledResult(disabledReason); + return { + overlayDatabaseMode: "none" /* None */, + useOverlayDatabaseCaching: false, + disabledReason: void 0 + }; } if (buildMode !== "none" /* None */ && (await Promise.all( languages.map( @@ -106580,7 +106617,7 @@ async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, b return { overlayDatabaseMode, useOverlayDatabaseCaching, - disabledReason + disabledReason: void 0 }; } function dbLocationOrDefault(dbLocation, tempDir) { diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts index d5df03129..0708c3d08 100644 --- a/src/config-utils.test.ts +++ b/src/config-utils.test.ts @@ -1165,6 +1165,7 @@ test( { overlayDatabaseMode: OverlayDatabaseMode.None, useOverlayDatabaseCaching: false, + disabledReason: OverlayDisabledReason.NotPullRequestOrDefaultBranch, }, ); diff --git a/src/config-utils.ts b/src/config-utils.ts index 214361c95..af1548eab 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -655,17 +655,21 @@ const OVERLAY_ANALYSIS_CODE_SCANNING_FEATURES: Record = { /** * Checks whether the overlay analysis feature is enabled for the given - * languages and configuration, returning the specific reason it is disabled, - * or `undefined` if it is enabled. + * languages and configuration. */ -async function getOverlayFeatureDisabledReason( +async function checkOverlayAnalysisFeatureEnabled( features: FeatureEnablement, codeql: CodeQL, languages: Language[], codeScanningConfig: UserConfig, -): Promise { +): Promise< + { enabled: true } | { enabled: false; reason: OverlayDisabledReason } +> { if (!(await features.getValue(Feature.OverlayAnalysis, codeql))) { - return OverlayDisabledReason.OverallFeatureNotEnabled; + return { + enabled: false, + reason: OverlayDisabledReason.OverallFeatureNotEnabled, + }; } let enableForCodeScanningOnly = false; for (const language of languages) { @@ -682,7 +686,7 @@ async function getOverlayFeatureDisabledReason( enableForCodeScanningOnly = true; continue; } - return OverlayDisabledReason.LanguageNotEnabled; + return { enabled: false, reason: OverlayDisabledReason.LanguageNotEnabled }; } if (enableForCodeScanningOnly) { // A code-scanning configuration runs only the (default) code-scanning suite @@ -694,10 +698,13 @@ async function getOverlayFeatureDisabledReason( codeScanningConfig.queries === undefined && codeScanningConfig["query-filters"] === undefined; if (!isCodeScanningOnly) { - return OverlayDisabledReason.NonDefaultQueries; + return { + enabled: false, + reason: OverlayDisabledReason.NonDefaultQueries, + }; } } - return undefined; + return { enabled: true }; } /** Checks if the runner has enough disk space for overlay analysis. */ @@ -756,30 +763,30 @@ async function runnerHasSufficientMemory( /** * Checks if the runner has sufficient disk space and memory for overlay - * analysis, returning the specific reason if not, or `undefined` if resources - * are sufficient. + * analysis. */ -async function getResourceDisabledReason( +async function checkRunnerResources( codeql: CodeQL, - diskUsage: DiskUsage | undefined, + diskUsage: DiskUsage, ramInput: string | undefined, logger: Logger, useV2ResourceChecks: boolean, -): Promise { - if (diskUsage === undefined) { - logger.info( - `Unable to determine available disk space for overlay analysis. ` + - `Setting overlay database mode to ${OverlayDatabaseMode.None}.`, - ); - return OverlayDisabledReason.UnableToDetermineDiskUsage; - } +): Promise< + { sufficient: true } | { sufficient: false; reason: OverlayDisabledReason } +> { if (!runnerHasSufficientDiskSpace(diskUsage, logger, useV2ResourceChecks)) { - return OverlayDisabledReason.InsufficientDiskSpace; + return { + sufficient: false, + reason: OverlayDisabledReason.InsufficientDiskSpace, + }; } if (!(await runnerHasSufficientMemory(codeql, ramInput, logger))) { - return OverlayDisabledReason.InsufficientMemory; + return { + sufficient: false, + reason: OverlayDisabledReason.InsufficientMemory, + }; } - return undefined; + return { sufficient: true }; } /** @@ -819,9 +826,11 @@ export async function getOverlayDatabaseMode( useOverlayDatabaseCaching: boolean; disabledReason: OverlayDisabledReason | undefined; }> { - let overlayDatabaseMode = OverlayDatabaseMode.None; - let useOverlayDatabaseCaching = false; - let disabledReason: OverlayDisabledReason | undefined; + const disabledResult = (reason: OverlayDisabledReason | undefined) => ({ + overlayDatabaseMode: OverlayDatabaseMode.None, + useOverlayDatabaseCaching: false, + disabledReason: reason, + }); const modeEnv = process.env.CODEQL_OVERLAY_DATABASE_MODE; // Any unrecognized CODEQL_OVERLAY_DATABASE_MODE value will be ignored and @@ -831,98 +840,150 @@ export async function getOverlayDatabaseMode( modeEnv === OverlayDatabaseMode.OverlayBase || modeEnv === OverlayDatabaseMode.None ) { - overlayDatabaseMode = modeEnv; logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} ` + + `Setting overlay database mode to ${modeEnv} ` + "from the CODEQL_OVERLAY_DATABASE_MODE environment variable.", ); - } else if ( - repositoryProperties[RepositoryPropertyName.DISABLE_OVERLAY] === true - ) { + return validateOverlayDatabaseMode( + modeEnv, + false, + codeql, + languages, + sourceRoot, + buildMode, + gitVersion, + logger, + ); + } + + if (repositoryProperties[RepositoryPropertyName.DISABLE_OVERLAY] === true) { logger.info( `Setting overlay database mode to ${OverlayDatabaseMode.None} ` + `because the ${RepositoryPropertyName.DISABLE_OVERLAY} repository property is set to true.`, ); - overlayDatabaseMode = OverlayDatabaseMode.None; - disabledReason = OverlayDisabledReason.DisabledByRepositoryProperty; - } else if ( - (disabledReason = await getOverlayFeatureDisabledReason( - features, - codeql, - languages, - codeScanningConfig, - )) === undefined - ) { - const performResourceChecks = !(await features.getValue( - Feature.OverlayAnalysisSkipResourceChecks, - codeql, - )); - const useV2ResourceChecks = await features.getValue( - Feature.OverlayAnalysisResourceChecksV2, - ); - const checkOverlayStatus = await features.getValue( - Feature.OverlayAnalysisStatusCheck, - ); - const diskUsage = - performResourceChecks || checkOverlayStatus - ? await checkDiskUsage(logger) - : undefined; - let resourceDisabledReason: OverlayDisabledReason | undefined; - if ( - performResourceChecks && - (resourceDisabledReason = await getResourceDisabledReason( - codeql, - diskUsage, - ramInput, - logger, - useV2ResourceChecks, - )) !== undefined - ) { - overlayDatabaseMode = OverlayDatabaseMode.None; - disabledReason = resourceDisabledReason; - } else if (checkOverlayStatus && diskUsage === undefined) { - logger.warning( - `Unable to determine disk usage, therefore setting overlay database mode to ${OverlayDatabaseMode.None}.`, - ); - overlayDatabaseMode = OverlayDatabaseMode.None; - disabledReason = OverlayDisabledReason.UnableToDetermineDiskUsage; - } else if ( - checkOverlayStatus && - 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.", - ); - overlayDatabaseMode = OverlayDatabaseMode.None; - disabledReason = OverlayDisabledReason.SkippedDueToCachedStatus; - } else if (isAnalyzingPullRequest()) { - overlayDatabaseMode = OverlayDatabaseMode.Overlay; - useOverlayDatabaseCaching = true; - logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} ` + - "with caching because we are analyzing a pull request.", - ); - } else if (await isAnalyzingDefaultBranch()) { - overlayDatabaseMode = OverlayDatabaseMode.OverlayBase; - useOverlayDatabaseCaching = true; - logger.info( - `Setting overlay database mode to ${overlayDatabaseMode} ` + - "with caching because we are analyzing the default branch.", - ); - } + return disabledResult(OverlayDisabledReason.DisabledByRepositoryProperty); } - const disabledResult = (reason: OverlayDisabledReason | undefined) => ({ + const featureResult = await checkOverlayAnalysisFeatureEnabled( + features, + codeql, + languages, + codeScanningConfig, + ); + if (!featureResult.enabled) { + return disabledResult(featureResult.reason); + } + + const performResourceChecks = !(await features.getValue( + Feature.OverlayAnalysisSkipResourceChecks, + codeql, + )); + const useV2ResourceChecks = await features.getValue( + Feature.OverlayAnalysisResourceChecksV2, + ); + const checkOverlayStatus = await features.getValue( + Feature.OverlayAnalysisStatusCheck, + ); + const diskUsage = + performResourceChecks || checkOverlayStatus + ? await checkDiskUsage(logger) + : undefined; + if ( + (performResourceChecks || checkOverlayStatus) && + diskUsage === undefined + ) { + logger.warning( + `Unable to determine disk usage, therefore setting overlay database mode to ${OverlayDatabaseMode.None}.`, + ); + return disabledResult(OverlayDisabledReason.UnableToDetermineDiskUsage); + } + const resourceResult = + performResourceChecks && diskUsage + ? await checkRunnerResources( + codeql, + diskUsage, + ramInput, + logger, + useV2ResourceChecks, + ) + : { sufficient: true as const }; + if (!resourceResult.sufficient) { + return disabledResult(resourceResult.reason); + } + if ( + checkOverlayStatus && + 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.", + ); + return disabledResult(OverlayDisabledReason.SkippedDueToCachedStatus); + } + + let overlayDatabaseMode: OverlayDatabaseMode; + if (isAnalyzingPullRequest()) { + overlayDatabaseMode = OverlayDatabaseMode.Overlay; + logger.info( + `Setting overlay database mode to ${overlayDatabaseMode} ` + + "with caching because we are analyzing a pull request.", + ); + } else if (await isAnalyzingDefaultBranch()) { + overlayDatabaseMode = OverlayDatabaseMode.OverlayBase; + logger.info( + `Setting overlay database mode to ${overlayDatabaseMode} ` + + "with caching because we are analyzing the default branch.", + ); + } else { + return disabledResult(OverlayDisabledReason.NotPullRequestOrDefaultBranch); + } + + return validateOverlayDatabaseMode( + overlayDatabaseMode, + true, + codeql, + languages, + sourceRoot, + buildMode, + gitVersion, + logger, + ); +} + +/** + * Validates that the given overlay database mode is compatible with the current + * configuration (build mode, CodeQL version, git repository, git version). Returns + * the mode unchanged if all checks pass, or falls back to `None` with the + * appropriate disabled reason. + */ +async function validateOverlayDatabaseMode( + overlayDatabaseMode: OverlayDatabaseMode, + useOverlayDatabaseCaching: boolean, + codeql: CodeQL, + languages: Language[], + sourceRoot: string, + buildMode: BuildMode | undefined, + gitVersion: GitVersionInfo | undefined, + logger: Logger, +): Promise<{ + overlayDatabaseMode: OverlayDatabaseMode; + useOverlayDatabaseCaching: boolean; + disabledReason: OverlayDisabledReason | undefined; +}> { + const disabledResult = (reason: OverlayDisabledReason) => ({ overlayDatabaseMode: OverlayDatabaseMode.None, useOverlayDatabaseCaching: false, disabledReason: reason, }); if (overlayDatabaseMode === OverlayDatabaseMode.None) { - return disabledResult(disabledReason); + return { + overlayDatabaseMode: OverlayDatabaseMode.None, + useOverlayDatabaseCaching: false, + disabledReason: undefined, + }; } if ( @@ -983,7 +1044,7 @@ export async function getOverlayDatabaseMode( return { overlayDatabaseMode, useOverlayDatabaseCaching, - disabledReason, + disabledReason: undefined, }; } diff --git a/src/overlay/diagnostics.ts b/src/overlay/diagnostics.ts index f3b0c0e29..30121d1bb 100644 --- a/src/overlay/diagnostics.ts +++ b/src/overlay/diagnostics.ts @@ -31,6 +31,8 @@ export enum OverlayDisabledReason { * queries or packs, disables default queries, or specifies query filters. */ NonDefaultQueries = "non-default-queries", + /** We are not analyzing a pull request or the default branch. */ + NotPullRequestOrDefaultBranch = "not-pull-request-or-default-branch", /** The top-level overlay analysis feature flag is not enabled. */ OverallFeatureNotEnabled = "overall-feature-not-enabled", /** Overlay analysis was skipped because it previously failed with similar hardware resources. */