Merge pull request #3507 from github/henrymercer/overlay-repo-property

Add a repository property for disabling overlay
This commit is contained in:
Henry Mercer
2026-02-26 16:21:03 +00:00
committed by GitHub
19 changed files with 713 additions and 124 deletions
+12
View File
@@ -161268,6 +161268,18 @@ var core6 = __toESM(require_core());
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver2 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -107116,6 +107116,18 @@ function createCacheKeyHash(components) {
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver2 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -103659,6 +103659,18 @@ var core6 = __toESM(require_core());
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver2 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -164646,6 +164646,18 @@ var RiskAssessment = {
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver2 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+120 -38
View File
@@ -104282,9 +104282,14 @@ function getUnknownLanguagesError(languages) {
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var repositoryPropertyParsers = {
["github-codeql-disable-overlay" /* DISABLE_OVERLAY */]: parseBooleanRepositoryProperty,
["github-codeql-extra-queries" /* EXTRA_QUERIES */]: parseStringRepositoryProperty
};
async function loadPropertiesFromApi(gitHubVersion, logger, repositoryNwo) {
if (gitHubVersion.type === "GitHub Enterprise Server" /* GHES */) {
return {};
@@ -104300,16 +104305,20 @@ async function loadPropertiesFromApi(gitHubVersion, logger, repositoryNwo) {
logger.debug(
`Retrieved ${remoteProperties.length} repository properties: ${remoteProperties.map((p) => p.property_name).join(", ")}`
);
const knownProperties = new Set(Object.values(RepositoryPropertyName));
const properties = {};
for (const property of remoteProperties) {
if (property.property_name === void 0) {
throw new Error(
`Expected property object to have a 'property_name', but got: ${JSON.stringify(property)}`
`Expected repository property object to have a 'property_name', but got: ${JSON.stringify(property)}`
);
}
if (knownProperties.has(property.property_name)) {
properties[property.property_name] = property.value;
if (typeof property.value !== "string") {
throw new Error(
`Expected repository property '${property.property_name}' to have a string value, but got: ${JSON.stringify(property)}`
);
}
if (isKnownPropertyName(property.property_name)) {
setProperty2(properties, property.property_name, property.value, logger);
}
}
if (Object.keys(properties).length === 0) {
@@ -104331,6 +104340,26 @@ async function loadPropertiesFromApi(gitHubVersion, logger, repositoryNwo) {
);
}
}
function setProperty2(properties, name, value, logger) {
properties[name] = repositoryPropertyParsers[name](name, value, logger);
}
function parseBooleanRepositoryProperty(name, value, logger) {
if (value !== "true" && value !== "false") {
logger.warning(
`Repository property '${name}' has unexpected value '${value}'. Expected 'true' or 'false'. Defaulting to false.`
);
}
return value === "true";
}
function parseStringRepositoryProperty(_name, value) {
return value;
}
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
function isKnownPropertyName(name) {
return KNOWN_REPOSITORY_PROPERTY_NAMES.has(name);
}
// src/config/db-config.ts
function shouldCombine(inputValue) {
@@ -105753,6 +105782,64 @@ var KnownLanguage = /* @__PURE__ */ ((KnownLanguage2) => {
return KnownLanguage2;
})(KnownLanguage || {});
// src/overlay/diagnostics.ts
async function addOverlayDisablementDiagnostics(config, codeql, overlayDisabledReason) {
addNoLanguageDiagnostic(
config,
makeTelemetryDiagnostic(
"codeql-action/overlay-disabled",
"Overlay analysis disabled",
{
reason: overlayDisabledReason
}
)
);
if (overlayDisabledReason === "skipped-due-to-cached-status" /* SkippedDueToCachedStatus */) {
addNoLanguageDiagnostic(
config,
makeDiagnostic(
"codeql-action/overlay-disabled-due-to-cached-status",
"Skipped improved incremental analysis because it failed previously with similar hardware resources",
{
attributes: {
languages: config.languages
},
markdownMessage: `Improved incremental analysis was skipped because it previously failed for this repository with CodeQL version ${(await codeql.getVersion()).version} on a runner with similar hardware resources. Improved incremental analysis may require a significant amount of disk space for some repositories. If you want to enable improved incremental analysis, increase the disk space available to the runner. If that doesn't help, contact GitHub Support for further assistance.
Improved incremental analysis will be automatically retried when the next version of CodeQL is released. You can also manually trigger a retry by [removing](${"https://docs.github.com/en/actions/how-tos/manage-workflow-runs/manage-caches#deleting-cache-entries" /* DELETE_ACTIONS_CACHE_ENTRIES */}) \`codeql-overlay-status-*\` entries from the Actions cache.`,
severity: "note",
visibility: {
cliSummaryTable: true,
statusPage: true,
telemetry: false
}
}
)
);
}
if (overlayDisabledReason === "disabled-by-repository-property" /* DisabledByRepositoryProperty */) {
addNoLanguageDiagnostic(
config,
makeDiagnostic(
"codeql-action/overlay-disabled-by-repository-property",
"Improved incremental analysis disabled by repository property",
{
attributes: {
languages: config.languages
},
markdownMessage: `Improved incremental analysis has been disabled because the \`${"github-codeql-disable-overlay" /* DISABLE_OVERLAY */}\` repository property is set to \`true\`. To re-enable improved incremental analysis, set this property to \`false\` or remove it.`,
severity: "note",
visibility: {
cliSummaryTable: true,
statusPage: true,
telemetry: false
}
}
)
);
}
}
// src/overlay/status.ts
var fs5 = __toESM(require("fs"));
var path7 = __toESM(require("path"));
@@ -106219,16 +106306,22 @@ async function runnerSupportsOverlayAnalysis(diskUsage, ramInput, logger, useV2R
}
return true;
}
async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, buildMode, ramInput, codeScanningConfig, gitVersion, logger) {
async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, buildMode, ramInput, codeScanningConfig, repositoryProperties, gitVersion, logger) {
let overlayDatabaseMode = "none" /* None */;
let useOverlayDatabaseCaching = false;
let skippedDueToCachedStatus = false;
let disabledReason;
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.`
);
} else 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 (await isOverlayAnalysisFeatureEnabled(
features,
codeql,
@@ -106253,17 +106346,19 @@ async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, b
useV2ResourceChecks
)) {
overlayDatabaseMode = "none" /* None */;
disabledReason = "insufficient-resources" /* InsufficientResources */;
} 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 */;
skippedDueToCachedStatus = true;
disabledReason = "skipped-due-to-cached-status" /* SkippedDueToCachedStatus */;
} else if (isAnalyzingPullRequest()) {
overlayDatabaseMode = "overlay" /* Overlay */;
useOverlayDatabaseCaching = true;
@@ -106277,14 +106372,16 @@ async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, b
`Setting overlay database mode to ${overlayDatabaseMode} with caching because we are analyzing the default branch.`
);
}
} else {
disabledReason = "feature-not-enabled" /* FeatureNotEnabled */;
}
const nonOverlayAnalysis = {
const disabledResult = (reason) => ({
overlayDatabaseMode: "none" /* None */,
useOverlayDatabaseCaching: false,
skippedDueToCachedStatus
};
disabledReason: reason
});
if (overlayDatabaseMode === "none" /* None */) {
return nonOverlayAnalysis;
return disabledResult(disabledReason);
}
if (buildMode !== "none" /* None */ && (await Promise.all(
languages.map(
@@ -106298,36 +106395,36 @@ async function getOverlayDatabaseMode(codeql, features, languages, sourceRoot, b
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because build-mode is set to "${buildMode}" instead of "none". Falling back to creating a normal full database instead.`
);
return nonOverlayAnalysis;
return disabledResult("incompatible-build-mode" /* IncompatibleBuildMode */);
}
if (!await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION)) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. Falling back to creating a normal full database instead.`
);
return nonOverlayAnalysis;
return disabledResult("incompatible-codeql" /* IncompatibleCodeQl */);
}
if (await getGitRoot(sourceRoot) === void 0) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because the source root "${sourceRoot}" is not inside a git repository. Falling back to creating a normal full database instead.`
);
return nonOverlayAnalysis;
return disabledResult("no-git-root" /* NoGitRoot */);
}
if (gitVersion === void 0) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because the Git version could not be determined. Falling back to creating a normal full database instead.`
);
return nonOverlayAnalysis;
return disabledResult("incompatible-git" /* IncompatibleGit */);
}
if (!gitVersion.isAtLeast(GIT_MINIMUM_VERSION_FOR_OVERLAY)) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because the installed Git version is older than ${GIT_MINIMUM_VERSION_FOR_OVERLAY}. Falling back to creating a normal full database instead.`
);
return nonOverlayAnalysis;
return disabledResult("incompatible-git" /* IncompatibleGit */);
}
return {
overlayDatabaseMode,
useOverlayDatabaseCaching,
skippedDueToCachedStatus
disabledReason
};
}
function dbLocationOrDefault(dbLocation, tempDir) {
@@ -106419,7 +106516,7 @@ async function initConfig(features, inputs) {
const {
overlayDatabaseMode,
useOverlayDatabaseCaching,
skippedDueToCachedStatus: overlaySkippedDueToCachedStatus
disabledReason: overlayDisabledReason
} = await getOverlayDatabaseMode(
inputs.codeql,
inputs.features,
@@ -106428,6 +106525,7 @@ async function initConfig(features, inputs) {
config.buildMode,
inputs.ramInput,
config.computedConfig,
config.repositoryProperties,
gitVersion,
logger
);
@@ -106436,27 +106534,11 @@ async function initConfig(features, inputs) {
);
config.overlayDatabaseMode = overlayDatabaseMode;
config.useOverlayDatabaseCaching = useOverlayDatabaseCaching;
if (overlaySkippedDueToCachedStatus) {
addNoLanguageDiagnostic(
if (overlayDisabledReason !== void 0) {
await addOverlayDisablementDiagnostics(
config,
makeDiagnostic(
"codeql-action/overlay-skipped-due-to-cached-status",
"Skipped improved incremental analysis because it failed previously with similar hardware resources",
{
attributes: {
languages: config.languages
},
markdownMessage: `Improved incremental analysis was skipped because it previously failed for this repository with CodeQL version ${(await inputs.codeql.getVersion()).version} on a runner with similar hardware resources. Improved incremental analysis may require a significant amount of disk space for some repositories. If you want to enable improved incremental analysis, increase the disk space available to the runner. If that doesn't help, contact GitHub Support for further assistance.
Improved incremental analysis will be automatically retried when the next version of CodeQL is released. You can also manually trigger a retry by [removing](${"https://docs.github.com/en/actions/how-tos/manage-workflow-runs/manage-caches#deleting-cache-entries" /* DELETE_ACTIONS_CACHE_ENTRIES */}) \`codeql-overlay-status-*\` entries from the Actions cache.`,
severity: "note",
visibility: {
cliSummaryTable: true,
statusPage: true,
telemetry: true
}
}
)
inputs.codeql,
overlayDisabledReason
);
}
if (overlayDatabaseMode === "overlay" /* Overlay */ || await shouldPerformDiffInformedAnalysis(
+12
View File
@@ -103658,6 +103658,18 @@ var core6 = __toESM(require_core());
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver2 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -104652,6 +104652,18 @@ var supportedAnalysisKinds = new Set(Object.values(AnalysisKind));
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver5 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -160903,6 +160903,18 @@ var core6 = __toESM(require_core());
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver2 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -121259,6 +121259,18 @@ var supportedAnalysisKinds = new Set(Object.values(AnalysisKind));
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver5 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -106711,6 +106711,18 @@ var core6 = __toESM(require_core());
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver2 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -161053,6 +161053,18 @@ var core6 = __toESM(require_core());
// src/config/db-config.ts
var jsonschema = __toESM(require_lib5());
var semver2 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+12
View File
@@ -107383,6 +107383,18 @@ var path7 = __toESM(require("path"));
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver5 = __toESM(require_semver2());
// src/feature-flags/properties.ts
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
// src/config/db-config.ts
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
+3 -3
View File
@@ -15,10 +15,10 @@ import { CliError } from "./cli-errors";
import * as codeql from "./codeql";
import {
AugmentationProperties,
Config,
defaultAugmentationProperties,
generateCodeScanningConfig,
} from "./config-utils";
defaultAugmentationProperties,
} from "./config/db-config";
import type { Config } from "./config-utils";
import * as defaults from "./defaults.json";
import { DocUrl } from "./doc-url";
import { KnownLanguage } from "./languages";
+107 -20
View File
@@ -11,14 +11,17 @@ import { AnalysisKind, supportedAnalysisKinds } from "./analyses";
import * as api from "./api-client";
import { CachingKind } from "./caching-utils";
import { createStubCodeQL } from "./codeql";
import { UserConfig } from "./config/db-config";
import * as configUtils from "./config-utils";
import * as errorMessages from "./error-messages";
import { Feature } from "./feature-flags";
import { RepositoryProperties } from "./feature-flags/properties";
import * as gitUtils from "./git-utils";
import { GitVersionInfo } from "./git-utils";
import { KnownLanguage, Language } from "./languages";
import { getRunnerLogger } from "./logging";
import { CODEQL_OVERLAY_MINIMUM_VERSION, OverlayDatabaseMode } from "./overlay";
import { OverlayDisabledReason } from "./overlay/diagnostics";
import * as overlayStatus from "./overlay/status";
import { parseRepositoryNwo } from "./repository";
import {
@@ -246,7 +249,7 @@ test("initActionState doesn't throw if there are queries configured in the repos
};
// Expected configuration for a CQ-only analysis.
const computedConfig: configUtils.UserConfig = {
const computedConfig: UserConfig = {
"disable-default-queries": true,
queries: [{ uses: "code-quality" }],
"query-filters": [],
@@ -491,7 +494,7 @@ test("load non-empty input", async (t) => {
fs.mkdirSync(path.join(tempDir, "foo"));
const userConfig: configUtils.UserConfig = {
const userConfig: UserConfig = {
name: "my config",
"disable-default-queries": true,
queries: [{ uses: "./foo" }],
@@ -979,10 +982,11 @@ interface OverlayDatabaseModeTestSetup {
codeqlVersion: string;
gitRoot: string | undefined;
gitVersion: GitVersionInfo | undefined;
codeScanningConfig: configUtils.UserConfig;
codeScanningConfig: UserConfig;
diskUsage: DiskUsage | undefined;
memoryFlagValue: number;
shouldSkipOverlayAnalysisDueToCachedStatus: boolean;
repositoryProperties: RepositoryProperties;
}
const defaultOverlayDatabaseModeTestSetup: OverlayDatabaseModeTestSetup = {
@@ -1005,6 +1009,7 @@ const defaultOverlayDatabaseModeTestSetup: OverlayDatabaseModeTestSetup = {
},
memoryFlagValue: 6920,
shouldSkipOverlayAnalysisDueToCachedStatus: false,
repositoryProperties: {},
};
const getOverlayDatabaseModeMacro = test.macro({
@@ -1015,7 +1020,7 @@ const getOverlayDatabaseModeMacro = test.macro({
expected: {
overlayDatabaseMode: OverlayDatabaseMode;
useOverlayDatabaseCaching: boolean;
skippedDueToCachedStatus?: boolean;
disabledReason?: OverlayDisabledReason;
},
) => {
return await withTmpDir(async (tempDir) => {
@@ -1082,14 +1087,16 @@ const getOverlayDatabaseModeMacro = test.macro({
setup.buildMode,
undefined,
setup.codeScanningConfig,
setup.repositoryProperties,
setup.gitVersion,
logger,
);
t.deepEqual(result, {
skippedDueToCachedStatus: false,
...expected,
});
if (!("disabledReason" in expected)) {
expected.disabledReason = undefined;
}
t.deepEqual(result, expected);
} finally {
// Restore the original environment
process.env = originalEnv;
@@ -1144,6 +1151,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1182,7 +1190,7 @@ test(
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
codeScanningConfig: {
packs: ["some-custom-pack@1.0.0"],
} as configUtils.UserConfig,
} as UserConfig,
isDefaultBranch: true,
},
{
@@ -1226,6 +1234,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.InsufficientResources,
},
);
@@ -1244,6 +1253,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.InsufficientResources,
},
);
@@ -1288,6 +1298,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.InsufficientResources,
},
);
@@ -1331,6 +1342,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.InsufficientResources,
},
);
@@ -1349,6 +1361,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.InsufficientResources,
},
);
@@ -1387,7 +1400,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
skippedDueToCachedStatus: true,
disabledReason: OverlayDisabledReason.SkippedDueToCachedStatus,
},
);
@@ -1407,7 +1420,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
skippedDueToCachedStatus: true,
disabledReason: OverlayDisabledReason.SkippedDueToCachedStatus,
},
);
@@ -1422,12 +1435,13 @@ test(
],
codeScanningConfig: {
"disable-default-queries": true,
} as configUtils.UserConfig,
} as UserConfig,
isDefaultBranch: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1442,12 +1456,13 @@ test(
],
codeScanningConfig: {
packs: ["some-custom-pack@1.0.0"],
} as configUtils.UserConfig,
} as UserConfig,
isDefaultBranch: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1462,12 +1477,13 @@ test(
],
codeScanningConfig: {
queries: [{ uses: "some-query.ql" }],
} as configUtils.UserConfig,
} as UserConfig,
isDefaultBranch: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1482,12 +1498,13 @@ test(
],
codeScanningConfig: {
"query-filters": [{ include: { "security-severity": "high" } }],
} as configUtils.UserConfig,
} as UserConfig,
isDefaultBranch: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1502,6 +1519,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1516,6 +1534,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1530,6 +1549,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1555,7 +1575,7 @@ test(
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
codeScanningConfig: {
packs: ["some-custom-pack@1.0.0"],
} as configUtils.UserConfig,
} as UserConfig,
isPullRequest: true,
},
{
@@ -1599,6 +1619,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.InsufficientResources,
},
);
@@ -1639,6 +1660,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.InsufficientResources,
},
);
@@ -1657,6 +1679,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.InsufficientResources,
},
);
@@ -1690,12 +1713,13 @@ test(
],
codeScanningConfig: {
"disable-default-queries": true,
} as configUtils.UserConfig,
} as UserConfig,
isPullRequest: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1710,12 +1734,13 @@ test(
],
codeScanningConfig: {
packs: ["some-custom-pack@1.0.0"],
} as configUtils.UserConfig,
} as UserConfig,
isPullRequest: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1730,12 +1755,13 @@ test(
],
codeScanningConfig: {
queries: [{ uses: "some-query.ql" }],
} as configUtils.UserConfig,
} as UserConfig,
isPullRequest: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1750,12 +1776,13 @@ test(
],
codeScanningConfig: {
"query-filters": [{ include: { "security-severity": "high" } }],
} as configUtils.UserConfig,
} as UserConfig,
isPullRequest: true,
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1770,6 +1797,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1784,6 +1812,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1798,6 +1827,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
@@ -1851,6 +1881,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.IncompatibleBuildMode,
},
);
@@ -1865,6 +1896,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.IncompatibleBuildMode,
},
);
@@ -1878,6 +1910,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.IncompatibleCodeQl,
},
);
@@ -1891,6 +1924,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.NoGitRoot,
},
);
@@ -1904,6 +1938,7 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.IncompatibleGit,
},
);
@@ -1917,6 +1952,57 @@ test(
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.IncompatibleGit,
},
);
test(
getOverlayDatabaseModeMacro,
"No overlay when disabled via repository property",
{
languages: [KnownLanguage.javascript],
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
isPullRequest: true,
repositoryProperties: {
"github-codeql-disable-overlay": true,
},
},
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.DisabledByRepositoryProperty,
},
);
test(
getOverlayDatabaseModeMacro,
"Overlay not disabled when repository property is false",
{
languages: [KnownLanguage.javascript],
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
isPullRequest: true,
repositoryProperties: {
"github-codeql-disable-overlay": false,
},
},
{
overlayDatabaseMode: OverlayDatabaseMode.Overlay,
useOverlayDatabaseCaching: true,
},
);
test(
getOverlayDatabaseModeMacro,
"Environment variable override takes precedence over repository property",
{
overlayDatabaseEnvVar: "overlay",
repositoryProperties: {
"github-codeql-disable-overlay": true,
},
},
{
overlayDatabaseMode: OverlayDatabaseMode.Overlay,
useOverlayDatabaseCaching: false,
},
);
@@ -1933,6 +2019,7 @@ for (const language in KnownLanguage) {
{
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
disabledReason: OverlayDisabledReason.FeatureNotEnabled,
},
);
}
+41 -44
View File
@@ -27,15 +27,16 @@ import {
} from "./config/db-config";
import {
addNoLanguageDiagnostic,
makeDiagnostic,
makeTelemetryDiagnostic,
} from "./diagnostics";
import { shouldPerformDiffInformedAnalysis } from "./diff-informed-analysis-utils";
import { DocUrl } from "./doc-url";
import { EnvVar } from "./environment";
import * as errorMessages from "./error-messages";
import { Feature, FeatureEnablement } from "./feature-flags";
import { RepositoryProperties } from "./feature-flags/properties";
import {
RepositoryProperties,
RepositoryPropertyName,
} from "./feature-flags/properties";
import {
getGeneratedFiles,
getGitRoot,
@@ -47,6 +48,10 @@ import {
import { KnownLanguage, Language } from "./languages";
import { Logger } from "./logging";
import { CODEQL_OVERLAY_MINIMUM_VERSION, OverlayDatabaseMode } from "./overlay";
import {
addOverlayDisablementDiagnostics,
OverlayDisabledReason,
} from "./overlay/diagnostics";
import { shouldSkipOverlayAnalysis } from "./overlay/status";
import { RepositoryNwo } from "./repository";
import { ToolsFeature } from "./tools-features";
@@ -66,8 +71,6 @@ import {
DiskUsage,
} from "./util";
export * from "./config/db-config";
/**
* The minimum available disk space (in MB) required to perform overlay analysis.
* If the available disk space on the runner is below the threshold when deciding
@@ -750,16 +753,17 @@ export async function getOverlayDatabaseMode(
buildMode: BuildMode | undefined,
ramInput: string | undefined,
codeScanningConfig: UserConfig,
repositoryProperties: RepositoryProperties,
gitVersion: GitVersionInfo | undefined,
logger: Logger,
): Promise<{
overlayDatabaseMode: OverlayDatabaseMode;
useOverlayDatabaseCaching: boolean;
skippedDueToCachedStatus: boolean;
disabledReason: OverlayDisabledReason | undefined;
}> {
let overlayDatabaseMode = OverlayDatabaseMode.None;
let useOverlayDatabaseCaching = false;
let skippedDueToCachedStatus = false;
let disabledReason: OverlayDisabledReason | undefined;
const modeEnv = process.env.CODEQL_OVERLAY_DATABASE_MODE;
// Any unrecognized CODEQL_OVERLAY_DATABASE_MODE value will be ignored and
@@ -774,6 +778,15 @@ export async function getOverlayDatabaseMode(
`Setting overlay database mode to ${overlayDatabaseMode} ` +
"from the CODEQL_OVERLAY_DATABASE_MODE environment variable.",
);
} else 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 (
await isOverlayAnalysisFeatureEnabled(
features,
@@ -806,11 +819,13 @@ export async function getOverlayDatabaseMode(
))
) {
overlayDatabaseMode = OverlayDatabaseMode.None;
disabledReason = OverlayDisabledReason.InsufficientResources;
} 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 &&
@@ -822,7 +837,7 @@ export async function getOverlayDatabaseMode(
"disk space, and CodeQL version.",
);
overlayDatabaseMode = OverlayDatabaseMode.None;
skippedDueToCachedStatus = true;
disabledReason = OverlayDisabledReason.SkippedDueToCachedStatus;
} else if (isAnalyzingPullRequest()) {
overlayDatabaseMode = OverlayDatabaseMode.Overlay;
useOverlayDatabaseCaching = true;
@@ -838,16 +853,18 @@ export async function getOverlayDatabaseMode(
"with caching because we are analyzing the default branch.",
);
}
} else {
disabledReason = OverlayDisabledReason.FeatureNotEnabled;
}
const nonOverlayAnalysis = {
const disabledResult = (reason: OverlayDisabledReason | undefined) => ({
overlayDatabaseMode: OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
skippedDueToCachedStatus,
};
disabledReason: reason,
});
if (overlayDatabaseMode === OverlayDatabaseMode.None) {
return nonOverlayAnalysis;
return disabledResult(disabledReason);
}
if (
@@ -870,7 +887,7 @@ export async function getOverlayDatabaseMode(
`build-mode is set to "${buildMode}" instead of "none". ` +
"Falling back to creating a normal full database instead.",
);
return nonOverlayAnalysis;
return disabledResult(OverlayDisabledReason.IncompatibleBuildMode);
}
if (!(await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION))) {
logger.warning(
@@ -878,7 +895,7 @@ export async function getOverlayDatabaseMode(
`the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. ` +
"Falling back to creating a normal full database instead.",
);
return nonOverlayAnalysis;
return disabledResult(OverlayDisabledReason.IncompatibleCodeQl);
}
if ((await getGitRoot(sourceRoot)) === undefined) {
logger.warning(
@@ -886,7 +903,7 @@ export async function getOverlayDatabaseMode(
`the source root "${sourceRoot}" is not inside a git repository. ` +
"Falling back to creating a normal full database instead.",
);
return nonOverlayAnalysis;
return disabledResult(OverlayDisabledReason.NoGitRoot);
}
if (gitVersion === undefined) {
logger.warning(
@@ -894,7 +911,7 @@ export async function getOverlayDatabaseMode(
"the Git version could not be determined. " +
"Falling back to creating a normal full database instead.",
);
return nonOverlayAnalysis;
return disabledResult(OverlayDisabledReason.IncompatibleGit);
}
if (!gitVersion.isAtLeast(GIT_MINIMUM_VERSION_FOR_OVERLAY)) {
logger.warning(
@@ -902,13 +919,13 @@ export async function getOverlayDatabaseMode(
`the installed Git version is older than ${GIT_MINIMUM_VERSION_FOR_OVERLAY}. ` +
"Falling back to creating a normal full database instead.",
);
return nonOverlayAnalysis;
return disabledResult(OverlayDisabledReason.IncompatibleGit);
}
return {
overlayDatabaseMode,
useOverlayDatabaseCaching,
skippedDueToCachedStatus,
disabledReason,
};
}
@@ -1058,7 +1075,7 @@ export async function initConfig(
const {
overlayDatabaseMode,
useOverlayDatabaseCaching,
skippedDueToCachedStatus: overlaySkippedDueToCachedStatus,
disabledReason: overlayDisabledReason,
} = await getOverlayDatabaseMode(
inputs.codeql,
inputs.features,
@@ -1067,6 +1084,7 @@ export async function initConfig(
config.buildMode,
inputs.ramInput,
config.computedConfig,
config.repositoryProperties,
gitVersion,
logger,
);
@@ -1077,32 +1095,11 @@ export async function initConfig(
config.overlayDatabaseMode = overlayDatabaseMode;
config.useOverlayDatabaseCaching = useOverlayDatabaseCaching;
if (overlaySkippedDueToCachedStatus) {
addNoLanguageDiagnostic(
if (overlayDisabledReason !== undefined) {
await addOverlayDisablementDiagnostics(
config,
makeDiagnostic(
"codeql-action/overlay-skipped-due-to-cached-status",
"Skipped improved incremental analysis because it failed previously with similar hardware resources",
{
attributes: {
languages: config.languages,
},
markdownMessage:
`Improved incremental analysis was skipped because it previously failed for this repository ` +
`with CodeQL version ${(await inputs.codeql.getVersion()).version} on a runner with similar hardware resources. ` +
"Improved incremental analysis may require a significant amount of disk space for some repositories. " +
"If you want to enable improved incremental analysis, increase the disk space available " +
"to the runner. If that doesn't help, contact GitHub Support for further assistance.\n\n" +
"Improved incremental analysis will be automatically retried when the next version of CodeQL is released. " +
`You can also manually trigger a retry by [removing](${DocUrl.DELETE_ACTIONS_CACHE_ENTRIES}) \`codeql-overlay-status-*\` entries from the Actions cache.`,
severity: "note",
visibility: {
cliSummaryTable: true,
statusPage: true,
telemetry: true,
},
},
),
inputs.codeql,
overlayDisabledReason,
);
}
+122 -2
View File
@@ -28,6 +28,9 @@ test("loadPropertiesFromApi throws if response data is not an array", async (t)
logger,
mockRepositoryNwo,
),
{
message: /Expected repository properties API to return an array/,
},
);
});
@@ -48,6 +51,9 @@ test("loadPropertiesFromApi throws if response data contains unexpected objects"
logger,
mockRepositoryNwo,
),
{
message: /Expected repository property object to have a 'property_name'/,
},
);
});
@@ -59,7 +65,7 @@ test("loadPropertiesFromApi returns empty object if on GHES", async (t) => {
data: [
{ property_name: "github-codeql-extra-queries", value: "+queries" },
{ property_name: "unknown-property", value: "something" },
] satisfies properties.RepositoryProperty[],
] satisfies properties.GitHubPropertiesResponse,
});
const logger = getRunnerLogger(true);
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
@@ -82,7 +88,7 @@ test("loadPropertiesFromApi loads known properties", async (t) => {
data: [
{ property_name: "github-codeql-extra-queries", value: "+queries" },
{ property_name: "unknown-property", value: "something" },
] satisfies properties.RepositoryProperty[],
] satisfies properties.GitHubPropertiesResponse,
});
const logger = getRunnerLogger(true);
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
@@ -95,3 +101,117 @@ test("loadPropertiesFromApi loads known properties", async (t) => {
);
t.deepEqual(response, { "github-codeql-extra-queries": "+queries" });
});
test("loadPropertiesFromApi parses true boolean property", async (t) => {
sinon.stub(api, "getRepositoryProperties").resolves({
headers: {},
status: 200,
url: "",
data: [
{
property_name: "github-codeql-disable-overlay",
value: "true",
},
{ property_name: "github-codeql-extra-queries", value: "+queries" },
] satisfies properties.GitHubPropertiesResponse,
});
const logger = getRunnerLogger(true);
const warningSpy = sinon.spy(logger, "warning");
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
const response = await properties.loadPropertiesFromApi(
{
type: util.GitHubVariant.DOTCOM,
},
logger,
mockRepositoryNwo,
);
t.deepEqual(response, {
"github-codeql-disable-overlay": true,
"github-codeql-extra-queries": "+queries",
});
t.true(warningSpy.notCalled);
});
test("loadPropertiesFromApi parses false boolean property", async (t) => {
sinon.stub(api, "getRepositoryProperties").resolves({
headers: {},
status: 200,
url: "",
data: [
{
property_name: "github-codeql-disable-overlay",
value: "false",
},
] satisfies properties.GitHubPropertiesResponse,
});
const logger = getRunnerLogger(true);
const warningSpy = sinon.spy(logger, "warning");
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
const response = await properties.loadPropertiesFromApi(
{
type: util.GitHubVariant.DOTCOM,
},
logger,
mockRepositoryNwo,
);
t.deepEqual(response, {
"github-codeql-disable-overlay": false,
});
t.true(warningSpy.notCalled);
});
test("loadPropertiesFromApi throws if property value is not a string", async (t) => {
sinon.stub(api, "getRepositoryProperties").resolves({
headers: {},
status: 200,
url: "",
data: [{ property_name: "github-codeql-extra-queries", value: 123 }],
});
const logger = getRunnerLogger(true);
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
await t.throwsAsync(
properties.loadPropertiesFromApi(
{
type: util.GitHubVariant.DOTCOM,
},
logger,
mockRepositoryNwo,
),
{
message:
/Expected repository property 'github-codeql-extra-queries' to have a string value/,
},
);
});
test("loadPropertiesFromApi warns if boolean property has unexpected value", async (t) => {
sinon.stub(api, "getRepositoryProperties").resolves({
headers: {},
status: 200,
url: "",
data: [
{
property_name: "github-codeql-disable-overlay",
value: "yes",
},
] satisfies properties.GitHubPropertiesResponse,
});
const logger = getRunnerLogger(true);
const warningSpy = sinon.spy(logger, "warning");
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
const response = await properties.loadPropertiesFromApi(
{
type: util.GitHubVariant.DOTCOM,
},
logger,
mockRepositoryNwo,
);
t.deepEqual(response, {
"github-codeql-disable-overlay": false,
});
t.true(warningSpy.calledOnce);
t.is(
warningSpy.firstCall.args[0],
"Repository property 'github-codeql-disable-overlay' has unexpected value 'yes'. Expected 'true' or 'false'. Defaulting to false.",
);
});
+73 -16
View File
@@ -7,28 +7,43 @@ import { GitHubVariant, GitHubVersion } from "../util";
* Enumerates repository property names that have some meaning to us.
*/
export enum RepositoryPropertyName {
DISABLE_OVERLAY = "github-codeql-disable-overlay",
EXTRA_QUERIES = "github-codeql-extra-queries",
}
/** Parsed types of the known repository properties. */
type AllRepositoryProperties = {
[RepositoryPropertyName.DISABLE_OVERLAY]: boolean;
[RepositoryPropertyName.EXTRA_QUERIES]: string;
};
/** Parsed repository properties. */
export type RepositoryProperties = Partial<AllRepositoryProperties>;
/** Parsers that transform repository properties from the API response into typed values. */
const repositoryPropertyParsers: {
[K in RepositoryPropertyName]: (
name: K,
value: string,
logger: Logger,
) => AllRepositoryProperties[K];
} = {
[RepositoryPropertyName.DISABLE_OVERLAY]: parseBooleanRepositoryProperty,
[RepositoryPropertyName.EXTRA_QUERIES]: parseStringRepositoryProperty,
};
/**
* A repository property has a name and a value.
*/
export interface RepositoryProperty {
export interface GitHubRepositoryProperty {
property_name: string;
value: string;
}
/**
* The API returns a list of `RepositoryProperty` objects.
* The API returns a list of `GitHubRepositoryProperty` objects.
*/
type GitHubPropertiesResponse = RepositoryProperty[];
/**
* A partial mapping from `RepositoryPropertyName` to values.
*/
export type RepositoryProperties = Partial<
Record<RepositoryPropertyName, string>
>;
export type GitHubPropertiesResponse = GitHubRepositoryProperty[];
/**
* Retrieves all known repository properties from the API.
@@ -62,19 +77,22 @@ export async function loadPropertiesFromApi(
`Retrieved ${remoteProperties.length} repository properties: ${remoteProperties.map((p) => p.property_name).join(", ")}`,
);
const knownProperties = new Set(Object.values(RepositoryPropertyName));
const properties: RepositoryProperties = {};
for (const property of remoteProperties) {
if (property.property_name === undefined) {
throw new Error(
`Expected property object to have a 'property_name', but got: ${JSON.stringify(property)}`,
`Expected repository property object to have a 'property_name', but got: ${JSON.stringify(property)}`,
);
}
if (
knownProperties.has(property.property_name as RepositoryPropertyName)
) {
properties[property.property_name] = property.value;
if (typeof property.value !== "string") {
throw new Error(
`Expected repository property '${property.property_name}' to have a string value, but got: ${JSON.stringify(property)}`,
);
}
if (isKnownPropertyName(property.property_name)) {
setProperty(properties, property.property_name, property.value, logger);
}
}
@@ -98,3 +116,42 @@ export async function loadPropertiesFromApi(
);
}
}
/** Update the partial set of repository properties with the parsed value of the specified property. */
function setProperty<K extends RepositoryPropertyName>(
properties: RepositoryProperties,
name: K,
value: string,
logger: Logger,
): void {
properties[name] = repositoryPropertyParsers[name](name, value, logger);
}
/** Parse a boolean repository property. */
function parseBooleanRepositoryProperty(
name: string,
value: string,
logger: Logger,
): boolean {
if (value !== "true" && value !== "false") {
logger.warning(
`Repository property '${name}' has unexpected value '${value}'. Expected 'true' or 'false'. Defaulting to false.`,
);
}
return value === "true";
}
/** Parse a string repository property. */
function parseStringRepositoryProperty(_name: string, value: string): string {
return value;
}
/** Set of known repository property names, for fast lookups. */
const KNOWN_REPOSITORY_PROPERTY_NAMES = new Set<string>(
Object.values(RepositoryPropertyName),
);
/** Returns whether the given value is a known repository property name. */
function isKnownPropertyName(name: string): name is RepositoryPropertyName {
return KNOWN_REPOSITORY_PROPERTY_NAMES.has(name);
}
+113
View File
@@ -0,0 +1,113 @@
import { type CodeQL } from "../codeql";
import { type Config } from "../config-utils";
import {
addNoLanguageDiagnostic,
makeDiagnostic,
makeTelemetryDiagnostic,
} from "../diagnostics";
import { DocUrl } from "../doc-url";
import { RepositoryPropertyName } from "../feature-flags/properties";
/** Reason why overlay analysis was disabled. */
export enum OverlayDisabledReason {
/** Overlay analysis was disabled by a repository property. */
DisabledByRepositoryProperty = "disabled-by-repository-property",
/** Overlay analysis feature was not enabled. */
FeatureNotEnabled = "feature-not-enabled",
/** The build mode is incompatible with overlay analysis. */
IncompatibleBuildMode = "incompatible-build-mode",
/** The CodeQL CLI version is too old to support overlay analysis. */
IncompatibleCodeQl = "incompatible-codeql",
/** The Git version could not be determined or is too old. */
IncompatibleGit = "incompatible-git",
/** The runner does not have enough disk space or memory. */
InsufficientResources = "insufficient-resources",
/** The source root is not inside a git repository. */
NoGitRoot = "no-git-root",
/** Overlay analysis was skipped because it previously failed with similar hardware resources. */
SkippedDueToCachedStatus = "skipped-due-to-cached-status",
/** Disk usage could not be determined during the overlay status check. */
UnableToDetermineDiskUsage = "unable-to-determine-disk-usage",
}
/**
* Add diagnostics related to why overlay was disabled. This includes:
*
* - A telemetry diagnostic that logs the disablement reason.
* - User-facing diagnostics for specific disablement reasons that are
* actionable by the user.
*/
export async function addOverlayDisablementDiagnostics(
config: Config,
codeql: CodeQL,
overlayDisabledReason: OverlayDisabledReason,
): Promise<void> {
addNoLanguageDiagnostic(
config,
makeTelemetryDiagnostic(
"codeql-action/overlay-disabled",
"Overlay analysis disabled",
{
reason: overlayDisabledReason,
},
),
);
if (
overlayDisabledReason === OverlayDisabledReason.SkippedDueToCachedStatus
) {
addNoLanguageDiagnostic(
config,
makeDiagnostic(
"codeql-action/overlay-disabled-due-to-cached-status",
"Skipped improved incremental analysis because it failed previously with similar hardware resources",
{
attributes: {
languages: config.languages,
},
markdownMessage:
`Improved incremental analysis was skipped because it previously failed for this repository ` +
`with CodeQL version ${(await codeql.getVersion()).version} on a runner with similar hardware resources. ` +
"Improved incremental analysis may require a significant amount of disk space for some repositories. " +
"If you want to enable improved incremental analysis, increase the disk space available " +
"to the runner. If that doesn't help, contact GitHub Support for further assistance.\n\n" +
"Improved incremental analysis will be automatically retried when the next version of CodeQL is released. " +
`You can also manually trigger a retry by [removing](${DocUrl.DELETE_ACTIONS_CACHE_ENTRIES}) \`codeql-overlay-status-*\` entries from the Actions cache.`,
severity: "note",
visibility: {
cliSummaryTable: true,
statusPage: true,
telemetry: false,
},
},
),
);
}
if (
overlayDisabledReason === OverlayDisabledReason.DisabledByRepositoryProperty
) {
addNoLanguageDiagnostic(
config,
makeDiagnostic(
"codeql-action/overlay-disabled-by-repository-property",
"Improved incremental analysis disabled by repository property",
{
attributes: {
languages: config.languages,
},
markdownMessage:
"Improved incremental analysis has been disabled because the " +
`\`${RepositoryPropertyName.DISABLE_OVERLAY}\` repository property is set to \`true\`. ` +
"To re-enable improved incremental analysis, set this property to `false` or remove it.",
severity: "note",
visibility: {
cliSummaryTable: true,
statusPage: true,
telemetry: false,
},
},
),
);
}
}
+2 -1
View File
@@ -11,7 +11,8 @@ import * as semver from "semver";
import * as apiCompatibility from "./api-compatibility.json";
import type { CodeQL, VersionInfo } from "./codeql";
import type { Config, Pack } from "./config-utils";
import type { Pack } from "./config/db-config";
import type { Config } from "./config-utils";
import { EnvVar } from "./environment";
import { Language } from "./languages";
import { Logger } from "./logging";