build: refresh js files

This commit is contained in:
Chuan-kai Lin
2025-07-16 07:10:39 -07:00
parent 709cf22a66
commit 3fb562ddcc
14 changed files with 575 additions and 174 deletions

204
lib/config-utils.js generated
View File

@@ -58,6 +58,7 @@ exports.getConfig = getConfig;
exports.generateRegistries = generateRegistries;
exports.wrapEnvironment = wrapEnvironment;
exports.parseBuildModeInput = parseBuildModeInput;
exports.generateCodeScanningConfig = generateCodeScanningConfig;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const perf_hooks_1 = require("perf_hooks");
@@ -231,12 +232,12 @@ async function getRawLanguages(languagesInput, repository, logger) {
return { rawLanguages, autodetected };
}
/**
* Get the default config for when the user has not supplied one.
* Get the default config, populated without user configuration file.
*/
async function getDefaultConfig({ languagesInput, queriesInput, qualityQueriesInput, packsInput, buildModeInput, dbLocation, trapCachingEnabled, dependencyCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeql, sourceRoot, githubVersion, features, logger, }) {
async function getDefaultConfig({ languagesInput, queriesInput, qualityQueriesInput, packsInput, buildModeInput, dbLocation, trapCachingEnabled, dependencyCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeql, githubVersion, features, logger, }) {
const languages = await getLanguages(codeql, languagesInput, repository, logger);
const buildMode = await parseBuildModeInput(buildModeInput, languages, features, logger);
const augmentationProperties = await calculateAugmentation(codeql, repository, features, packsInput, queriesInput, qualityQueriesInput, languages, sourceRoot, buildMode, logger);
const augmentationProperties = await calculateAugmentation(packsInput, queriesInput, qualityQueriesInput, languages);
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(trapCachingEnabled, codeql, languages, logger);
return {
languages,
@@ -265,11 +266,7 @@ async function downloadCacheWithTime(trapCachingEnabled, codeQL, languages, logg
}
return { trapCaches, trapCacheDownloadTime };
}
/**
* Load the config from the given file.
*/
async function loadConfig({ languagesInput, queriesInput, qualityQueriesInput, packsInput, buildModeInput, configFile, dbLocation, trapCachingEnabled, dependencyCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeql, workspacePath, sourceRoot, githubVersion, apiDetails, features, logger, }) {
let parsedYAML;
async function loadUserConfig(configFile, workspacePath, apiDetails, tempDir) {
if (isLocal(configFile)) {
if (configFile !== userConfigFromActionPath(tempDir)) {
// If the config file is not generated by the Action, it should be relative to the workspace.
@@ -279,31 +276,11 @@ async function loadConfig({ languagesInput, queriesInput, qualityQueriesInput, p
throw new util_1.ConfigurationError(getConfigFileOutsideWorkspaceErrorMessage(configFile));
}
}
parsedYAML = getLocalConfig(configFile);
return getLocalConfig(configFile);
}
else {
parsedYAML = await getRemoteConfig(configFile, apiDetails);
return await getRemoteConfig(configFile, apiDetails);
}
const languages = await getLanguages(codeql, languagesInput, repository, logger);
const buildMode = await parseBuildModeInput(buildModeInput, languages, features, logger);
const augmentationProperties = await calculateAugmentation(codeql, repository, features, packsInput, queriesInput, qualityQueriesInput, languages, sourceRoot, buildMode, logger);
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(trapCachingEnabled, codeql, languages, logger);
return {
languages,
buildMode,
originalUserInput: parsedYAML,
tempDir,
codeQLCmd: codeql.getPath(),
gitHubVersion: githubVersion,
dbLocation: dbLocationOrDefault(dbLocation, tempDir),
debugMode,
debugArtifactName,
debugDatabaseName,
augmentationProperties,
trapCaches,
trapCacheDownloadTime,
dependencyCachingEnabled: (0, caching_utils_1.getCachingKind)(dependencyCachingEnabled),
};
}
/**
* Calculates how the codeql config file needs to be augmented before passing
@@ -312,17 +289,11 @@ async function loadConfig({ languagesInput, queriesInput, qualityQueriesInput, p
* and the CLI does not know about these inputs so we need to inject them into
* the config file sent to the CLI.
*
* @param codeql The CodeQL object.
* @param repository The repository to analyze.
* @param features The feature enablement object.
* @param rawPacksInput The packs input from the action configuration.
* @param rawQueriesInput The queries input from the action configuration.
* @param languages The languages that the config file is for. If the packs input
* is non-empty, then there must be exactly one language. Otherwise, an
* error is thrown.
* @param sourceRoot The source root of the repository.
* @param buildMode The build mode to use.
* @param logger The logger to use for logging.
*
* @returns The properties that need to be augmented in the config file.
*
@@ -330,30 +301,21 @@ async function loadConfig({ languagesInput, queriesInput, qualityQueriesInput, p
* not have exactly one language.
*/
// exported for testing.
async function calculateAugmentation(codeql, repository, features, rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages, sourceRoot, buildMode, logger) {
async function calculateAugmentation(rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages) {
const packsInputCombines = shouldCombine(rawPacksInput);
const packsInput = parsePacksFromInput(rawPacksInput, languages, packsInputCombines);
const queriesInputCombines = shouldCombine(rawQueriesInput);
const queriesInput = parseQueriesFromInput(rawQueriesInput, queriesInputCombines);
const { overlayDatabaseMode, useOverlayDatabaseCaching } = await getOverlayDatabaseMode(codeql, repository, features, languages, sourceRoot, buildMode, logger);
logger.info(`Using overlay database mode: ${overlayDatabaseMode} ` +
`${useOverlayDatabaseCaching ? "with" : "without"} caching.`);
const qualityQueriesInput = parseQueriesFromInput(rawQualityQueriesInput, false);
const extraQueryExclusions = [];
if (await (0, diff_informed_analysis_utils_1.shouldPerformDiffInformedAnalysis)(codeql, features, logger)) {
extraQueryExclusions.push({
exclude: { tags: "exclude-from-incremental" },
});
}
return {
packsInputCombines,
packsInput: packsInput?.[languages[0]],
queriesInput,
queriesInputCombines,
qualityQueriesInput,
extraQueryExclusions,
overlayDatabaseMode,
useOverlayDatabaseCaching,
extraQueryExclusions: [],
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
};
}
function parseQueriesFromInput(rawQueriesInput, queriesInputCombines) {
@@ -368,6 +330,64 @@ function parseQueriesFromInput(rawQueriesInput, queriesInputCombines) {
}
return trimmedInput.split(",").map((query) => ({ uses: query.trim() }));
}
const OVERLAY_ANALYSIS_FEATURES = {
actions: feature_flags_1.Feature.OverlayAnalysisActions,
cpp: feature_flags_1.Feature.OverlayAnalysisCpp,
csharp: feature_flags_1.Feature.OverlayAnalysisCsharp,
go: feature_flags_1.Feature.OverlayAnalysisGo,
java: feature_flags_1.Feature.OverlayAnalysisJava,
javascript: feature_flags_1.Feature.OverlayAnalysisJavascript,
python: feature_flags_1.Feature.OverlayAnalysisPython,
ruby: feature_flags_1.Feature.OverlayAnalysisRuby,
rust: feature_flags_1.Feature.OverlayAnalysisRust,
swift: feature_flags_1.Feature.OverlayAnalysisSwift,
};
const OVERLAY_ANALYSIS_CODE_SCANNING_FEATURES = {
actions: feature_flags_1.Feature.OverlayAnalysisCodeScanningActions,
cpp: feature_flags_1.Feature.OverlayAnalysisCodeScanningCpp,
csharp: feature_flags_1.Feature.OverlayAnalysisCodeScanningCsharp,
go: feature_flags_1.Feature.OverlayAnalysisCodeScanningGo,
java: feature_flags_1.Feature.OverlayAnalysisCodeScanningJava,
javascript: feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
python: feature_flags_1.Feature.OverlayAnalysisCodeScanningPython,
ruby: feature_flags_1.Feature.OverlayAnalysisCodeScanningRuby,
rust: feature_flags_1.Feature.OverlayAnalysisCodeScanningRust,
swift: feature_flags_1.Feature.OverlayAnalysisCodeScanningSwift,
};
async function isOverlayAnalysisFeatureEnabled(repository, features, codeql, languages, codeScanningConfig) {
// TODO: Remove the repository owner check once support for overlay analysis
// stabilizes, and no more backward-incompatible changes are expected.
if (!["github", "dsp-testing"].includes(repository.owner)) {
return false;
}
if (!(await features.getValue(feature_flags_1.Feature.OverlayAnalysis, codeql))) {
return false;
}
let enableForCodeScanningOnly = false;
for (const language of languages) {
const feature = OVERLAY_ANALYSIS_FEATURES[language];
if (feature && (await features.getValue(feature, codeql))) {
continue;
}
const codeScanningFeature = OVERLAY_ANALYSIS_CODE_SCANNING_FEATURES[language];
if (codeScanningFeature &&
(await features.getValue(codeScanningFeature, codeql))) {
enableForCodeScanningOnly = true;
continue;
}
return false;
}
if (enableForCodeScanningOnly) {
// A code-scanning configuration runs only the (default) code-scanning suite
// if the default queries are not disabled, and no packs, queries, or
// query-filters are specified.
return (codeScanningConfig["disable-default-queries"] !== true &&
codeScanningConfig.packs === undefined &&
codeScanningConfig.queries === undefined &&
codeScanningConfig["query-filters"] === undefined);
}
return true;
}
/**
* Calculate and validate the overlay database mode and caching to use.
*
@@ -389,7 +409,7 @@ function parseQueriesFromInput(rawQueriesInput, queriesInputCombines) {
* @returns An object containing the overlay database mode and whether the
* action should perform overlay-base database caching.
*/
async function getOverlayDatabaseMode(codeql, repository, features, languages, sourceRoot, buildMode, logger) {
async function getOverlayDatabaseMode(codeql, repository, features, languages, sourceRoot, buildMode, codeScanningConfig, logger) {
let overlayDatabaseMode = overlay_database_utils_1.OverlayDatabaseMode.None;
let useOverlayDatabaseCaching = false;
const modeEnv = process.env.CODEQL_OVERLAY_DATABASE_MODE;
@@ -402,11 +422,7 @@ async function getOverlayDatabaseMode(codeql, repository, features, languages, s
logger.info(`Setting overlay database mode to ${overlayDatabaseMode} ` +
"from the CODEQL_OVERLAY_DATABASE_MODE environment variable.");
}
else if (
// TODO: Remove the repository owner check once support for overlay analysis
// stabilizes, and no more backward-incompatible changes are expected.
["github", "dsp-testing"].includes(repository.owner) &&
(await features.getValue(feature_flags_1.Feature.OverlayAnalysis, codeql))) {
else if (await isOverlayAnalysisFeatureEnabled(repository, features, codeql, languages, codeScanningConfig)) {
if ((0, actions_util_1.isAnalyzingPullRequest)()) {
overlayDatabaseMode = overlay_database_utils_1.OverlayDatabaseMode.Overlay;
useOverlayDatabaseCaching = true;
@@ -586,7 +602,6 @@ function userConfigFromActionPath(tempDir) {
* a default config. The parsed config is then stored to a known location.
*/
async function initConfig(inputs) {
let config;
const { logger, tempDir } = inputs;
// if configInput is set, it takes precedence over configFile
if (inputs.configInput) {
@@ -597,14 +612,31 @@ async function initConfig(inputs) {
fs.writeFileSync(inputs.configFile, inputs.configInput);
logger.debug(`Using config from action input: ${inputs.configFile}`);
}
// If no config file was provided create an empty one
let userConfig = {};
if (!inputs.configFile) {
logger.debug("No configuration file was provided");
config = await getDefaultConfig(inputs);
}
else {
// Convince the type checker that inputs.configFile is defined.
config = await loadConfig({ ...inputs, configFile: inputs.configFile });
logger.debug(`Using configuration file: ${inputs.configFile}`);
userConfig = await loadUserConfig(inputs.configFile, inputs.workspacePath, inputs.apiDetails, tempDir);
}
const config = await getDefaultConfig(inputs);
const augmentationProperties = config.augmentationProperties;
config.originalUserInput = userConfig;
// The choice of overlay database mode depends on the selection of languages
// and queries, which in turn depends on the user config and the augmentation
// properties. So we need to calculate the overlay database mode after the
// rest of the config has been populated.
const { overlayDatabaseMode, useOverlayDatabaseCaching } = await getOverlayDatabaseMode(inputs.codeql, inputs.repository, inputs.features, config.languages, inputs.sourceRoot, config.buildMode, generateCodeScanningConfig(userConfig, augmentationProperties), logger);
logger.info(`Using overlay database mode: ${overlayDatabaseMode} ` +
`${useOverlayDatabaseCaching ? "with" : "without"} caching.`);
augmentationProperties.overlayDatabaseMode = overlayDatabaseMode;
augmentationProperties.useOverlayDatabaseCaching = useOverlayDatabaseCaching;
if (overlayDatabaseMode === overlay_database_utils_1.OverlayDatabaseMode.Overlay ||
(await (0, diff_informed_analysis_utils_1.shouldPerformDiffInformedAnalysis)(inputs.codeql, inputs.features, logger))) {
augmentationProperties.extraQueryExclusions.push({
exclude: { tags: "exclude-from-incremental" },
});
}
// Save the config so we can easily access it again in the future
await saveConfig(config, logger);
@@ -807,4 +839,56 @@ async function parseBuildModeInput(input, languages, features, logger) {
}
return input;
}
function generateCodeScanningConfig(originalUserInput, augmentationProperties) {
// make a copy so we can modify it
const augmentedConfig = (0, util_1.cloneObject)(originalUserInput);
// Inject the queries from the input
if (augmentationProperties.queriesInput) {
if (augmentationProperties.queriesInputCombines) {
augmentedConfig.queries = (augmentedConfig.queries || []).concat(augmentationProperties.queriesInput);
}
else {
augmentedConfig.queries = augmentationProperties.queriesInput;
}
}
if (augmentedConfig.queries?.length === 0) {
delete augmentedConfig.queries;
}
// Inject the packs from the input
if (augmentationProperties.packsInput) {
if (augmentationProperties.packsInputCombines) {
// At this point, we already know that this is a single-language analysis
if (Array.isArray(augmentedConfig.packs)) {
augmentedConfig.packs = (augmentedConfig.packs || []).concat(augmentationProperties.packsInput);
}
else if (!augmentedConfig.packs) {
augmentedConfig.packs = augmentationProperties.packsInput;
}
else {
// At this point, we know there is only one language.
// If there were more than one language, an error would already have been thrown.
const language = Object.keys(augmentedConfig.packs)[0];
augmentedConfig.packs[language] = augmentedConfig.packs[language].concat(augmentationProperties.packsInput);
}
}
else {
augmentedConfig.packs = augmentationProperties.packsInput;
}
}
if (Array.isArray(augmentedConfig.packs) && !augmentedConfig.packs.length) {
delete augmentedConfig.packs;
}
augmentedConfig["query-filters"] = [
// Ordering matters. If the first filter is an inclusion, it implicitly
// excludes all queries that are not included. If it is an exclusion,
// it implicitly includes all queries that are not excluded. So user
// filters (if any) should always be first to preserve intent.
...(augmentedConfig["query-filters"] || []),
...augmentationProperties.extraQueryExclusions,
];
if (augmentedConfig["query-filters"]?.length === 0) {
delete augmentedConfig["query-filters"];
}
return augmentedConfig;
}
//# sourceMappingURL=config-utils.js.map