Support overlay database creation

This commit adds support for creating overlay-base and overlay
databases, controlled via the CODEQL_OVERLAY_DATABASE_MODE environment
variable.
This commit is contained in:
Chuan-kai Lin 2025-03-10 10:38:02 -07:00
parent 270886f805
commit ff5f0b9efd
4 changed files with 89 additions and 8 deletions

View file

@ -300,6 +300,28 @@ export const decodeGitFilePath = function (filePath: string): string {
return filePath; return filePath;
}; };
/**
* Get the root of the Git repository.
*
* @param sourceRoot The source root of the code being analyzed.
* @returns The root of the Git repository.
*/
export const getGitRoot = async function (
sourceRoot: string,
): Promise<string | undefined> {
try {
const stdout = await runGitCommand(
sourceRoot,
["rev-parse", "--show-toplevel"],
`Cannot find Git repository root from the source root ${sourceRoot}.`,
);
return stdout.trim();
} catch {
// Errors are already logged by runGitCommand()
return undefined;
}
};
function getRefFromEnv(): string { function getRefFromEnv(): string {
// To workaround a limitation of Actions dynamic workflows not setting // To workaround a limitation of Actions dynamic workflows not setting
// the GITHUB_REF in some cases, we accept also the ref within the // the GITHUB_REF in some cases, we accept also the ref within the

View file

@ -36,6 +36,7 @@ import { Feature, featureConfig, Features } from "./feature-flags";
import { import {
checkInstallPython311, checkInstallPython311,
cleanupDatabaseClusterDirectory, cleanupDatabaseClusterDirectory,
getOverlayDatabaseMode,
initCodeQL, initCodeQL,
initConfig, initConfig,
runInit, runInit,
@ -396,7 +397,22 @@ async function run() {
} }
try { try {
cleanupDatabaseClusterDirectory(config, logger); const sourceRoot = path.resolve(
getRequiredEnvParam("GITHUB_WORKSPACE"),
getOptionalInput("source-root") || "",
);
const overlayDatabaseMode = await getOverlayDatabaseMode(
(await codeql.getVersion()).version,
config,
sourceRoot,
logger,
);
logger.info(`Using overlay database mode: ${overlayDatabaseMode}`);
if (overlayDatabaseMode !== OverlayDatabaseMode.Overlay) {
cleanupDatabaseClusterDirectory(config, logger);
}
if (zstdAvailability) { if (zstdAvailability) {
await recordZstdAvailability(config, zstdAvailability); await recordZstdAvailability(config, zstdAvailability);
@ -676,11 +692,6 @@ async function run() {
} }
} }
const sourceRoot = path.resolve(
getRequiredEnvParam("GITHUB_WORKSPACE"),
getOptionalInput("source-root") || "",
);
const tracerConfig = await runInit( const tracerConfig = await runInit(
codeql, codeql,
config, config,
@ -688,7 +699,7 @@ async function run() {
"Runner.Worker.exe", "Runner.Worker.exe",
getOptionalInput("registries"), getOptionalInput("registries"),
apiDetails, apiDetails,
OverlayDatabaseMode.None, overlayDatabaseMode,
logger, logger,
); );
if (tracerConfig !== undefined) { if (tracerConfig !== undefined) {

View file

@ -3,15 +3,20 @@ import * as path from "path";
import * as toolrunner from "@actions/exec/lib/toolrunner"; import * as toolrunner from "@actions/exec/lib/toolrunner";
import * as io from "@actions/io"; import * as io from "@actions/io";
import * as semver from "semver";
import { getOptionalInput, isSelfHostedRunner } from "./actions-util"; import { getOptionalInput, isSelfHostedRunner } from "./actions-util";
import { GitHubApiCombinedDetails, GitHubApiDetails } from "./api-client"; import { GitHubApiCombinedDetails, GitHubApiDetails } from "./api-client";
import { CodeQL, setupCodeQL } from "./codeql"; import { CodeQL, setupCodeQL } from "./codeql";
import * as configUtils from "./config-utils"; import * as configUtils from "./config-utils";
import { CodeQLDefaultVersionInfo, FeatureEnablement } from "./feature-flags"; import { CodeQLDefaultVersionInfo, FeatureEnablement } from "./feature-flags";
import { getGitRoot } from "./git-utils";
import { Language, isScannedLanguage } from "./languages"; import { Language, isScannedLanguage } from "./languages";
import { Logger } from "./logging"; import { Logger } from "./logging";
import { OverlayDatabaseMode } from "./overlay-database-utils"; import {
CODEQL_OVERLAY_MINIMUM_VERSION,
OverlayDatabaseMode,
} from "./overlay-database-utils";
import { ToolsSource } from "./setup-codeql"; import { ToolsSource } from "./setup-codeql";
import { ZstdAvailability } from "./tar"; import { ZstdAvailability } from "./tar";
import { ToolsDownloadStatusReport } from "./tools-download"; import { ToolsDownloadStatusReport } from "./tools-download";
@ -80,6 +85,47 @@ export async function initConfig(
return config; return config;
} }
export async function getOverlayDatabaseMode(
codeqlVersion: string,
config: configUtils.Config,
sourceRoot: string,
logger: Logger,
): Promise<OverlayDatabaseMode> {
const overlayDatabaseMode = process.env.CODEQL_OVERLAY_DATABASE_MODE;
if (
overlayDatabaseMode === OverlayDatabaseMode.Overlay ||
overlayDatabaseMode === OverlayDatabaseMode.OverlayBase
) {
if (config.buildMode !== util.BuildMode.None) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because ` +
`build-mode is set to "${config.buildMode}" instead of "none". ` +
"Falling back to creating a normal full database instead.",
);
return OverlayDatabaseMode.None;
}
if (semver.lt(codeqlVersion, 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 OverlayDatabaseMode.None;
}
if ((await getGitRoot(sourceRoot)) === undefined) {
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 OverlayDatabaseMode.None;
}
return overlayDatabaseMode as OverlayDatabaseMode;
}
return OverlayDatabaseMode.None;
}
export async function runInit( export async function runInit(
codeql: CodeQL, codeql: CodeQL,
config: configUtils.Config, config: configUtils.Config,

View file

@ -3,3 +3,5 @@ export enum OverlayDatabaseMode {
OverlayBase = "overlay-base", OverlayBase = "overlay-base",
None = "none", None = "none",
} }
export const CODEQL_OVERLAY_MINIMUM_VERSION = "2.20.5";