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

55
lib/codeql.js generated
View File

@@ -50,6 +50,7 @@ const toolrunner = __importStar(require("@actions/exec/lib/toolrunner"));
const yaml = __importStar(require("js-yaml")); const yaml = __importStar(require("js-yaml"));
const actions_util_1 = require("./actions-util"); const actions_util_1 = require("./actions-util");
const cli_errors_1 = require("./cli-errors"); const cli_errors_1 = require("./cli-errors");
const config_utils_1 = require("./config-utils");
const doc_url_1 = require("./doc-url"); const doc_url_1 = require("./doc-url");
const environment_1 = require("./environment"); const environment_1 = require("./environment");
const feature_flags_1 = require("./feature-flags"); const feature_flags_1 = require("./feature-flags");
@@ -261,7 +262,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
extraArgs.push(...(await getTrapCachingExtractorConfigArgs(config))); extraArgs.push(...(await getTrapCachingExtractorConfigArgs(config)));
extraArgs.push(`--trace-process-name=${processName}`); extraArgs.push(`--trace-process-name=${processName}`);
} }
const codeScanningConfigFile = await generateCodeScanningConfig(config, logger); const codeScanningConfigFile = await writeCodeScanningConfigFile(config, logger);
const externalRepositoryToken = (0, actions_util_1.getOptionalInput)("external-repository-token"); const externalRepositoryToken = (0, actions_util_1.getOptionalInput)("external-repository-token");
extraArgs.push(`--codescanning-config=${codeScanningConfigFile}`); extraArgs.push(`--codescanning-config=${codeScanningConfigFile}`);
if (externalRepositoryToken) { if (externalRepositoryToken) {
@@ -756,57 +757,9 @@ async function runCli(cmd, args = [], opts = {}) {
* @param config The configuration to use. * @param config The configuration to use.
* @returns the path to the generated user configuration file. * @returns the path to the generated user configuration file.
*/ */
async function generateCodeScanningConfig(config, logger) { async function writeCodeScanningConfigFile(config, logger) {
const codeScanningConfigFile = getGeneratedCodeScanningConfigPath(config); const codeScanningConfigFile = getGeneratedCodeScanningConfigPath(config);
// make a copy so we can modify it const augmentedConfig = (0, config_utils_1.generateCodeScanningConfig)(config.originalUserInput, config.augmentationProperties);
const augmentedConfig = (0, util_1.cloneObject)(config.originalUserInput);
// Inject the queries from the input
if (config.augmentationProperties.queriesInput) {
if (config.augmentationProperties.queriesInputCombines) {
augmentedConfig.queries = (augmentedConfig.queries || []).concat(config.augmentationProperties.queriesInput);
}
else {
augmentedConfig.queries = config.augmentationProperties.queriesInput;
}
}
if (augmentedConfig.queries?.length === 0) {
delete augmentedConfig.queries;
}
// Inject the packs from the input
if (config.augmentationProperties.packsInput) {
if (config.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(config.augmentationProperties.packsInput);
}
else if (!augmentedConfig.packs) {
augmentedConfig.packs = config.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(config.augmentationProperties.packsInput);
}
}
else {
augmentedConfig.packs = config.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"] || []),
...(config.augmentationProperties.extraQueryExclusions || []),
];
if (augmentedConfig["query-filters"]?.length === 0) {
delete augmentedConfig["query-filters"];
}
logger.info(`Writing augmented user configuration file to ${codeScanningConfigFile}`); logger.info(`Writing augmented user configuration file to ${codeScanningConfigFile}`);
logger.startGroup("Augmented user configuration file contents"); logger.startGroup("Augmented user configuration file contents");
logger.info(yaml.dump(augmentedConfig)); logger.info(yaml.dump(augmentedConfig));

File diff suppressed because one or more lines are too long

204
lib/config-utils.js generated
View File

@@ -58,6 +58,7 @@ exports.getConfig = getConfig;
exports.generateRegistries = generateRegistries; exports.generateRegistries = generateRegistries;
exports.wrapEnvironment = wrapEnvironment; exports.wrapEnvironment = wrapEnvironment;
exports.parseBuildModeInput = parseBuildModeInput; exports.parseBuildModeInput = parseBuildModeInput;
exports.generateCodeScanningConfig = generateCodeScanningConfig;
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
const path = __importStar(require("path")); const path = __importStar(require("path"));
const perf_hooks_1 = require("perf_hooks"); const perf_hooks_1 = require("perf_hooks");
@@ -231,12 +232,12 @@ async function getRawLanguages(languagesInput, repository, logger) {
return { rawLanguages, autodetected }; 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 languages = await getLanguages(codeql, languagesInput, repository, logger);
const buildMode = await parseBuildModeInput(buildModeInput, languages, features, 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); const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(trapCachingEnabled, codeql, languages, logger);
return { return {
languages, languages,
@@ -265,11 +266,7 @@ async function downloadCacheWithTime(trapCachingEnabled, codeQL, languages, logg
} }
return { trapCaches, trapCacheDownloadTime }; return { trapCaches, trapCacheDownloadTime };
} }
/** async function loadUserConfig(configFile, workspacePath, apiDetails, tempDir) {
* 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;
if (isLocal(configFile)) { if (isLocal(configFile)) {
if (configFile !== userConfigFromActionPath(tempDir)) { if (configFile !== userConfigFromActionPath(tempDir)) {
// If the config file is not generated by the Action, it should be relative to the workspace. // 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)); throw new util_1.ConfigurationError(getConfigFileOutsideWorkspaceErrorMessage(configFile));
} }
} }
parsedYAML = getLocalConfig(configFile); return getLocalConfig(configFile);
} }
else { 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 * 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 * and the CLI does not know about these inputs so we need to inject them into
* the config file sent to the CLI. * 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 rawPacksInput The packs input from the action configuration.
* @param rawQueriesInput The queries 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 * @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 * is non-empty, then there must be exactly one language. Otherwise, an
* error is thrown. * 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. * @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. * not have exactly one language.
*/ */
// exported for testing. // 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 packsInputCombines = shouldCombine(rawPacksInput);
const packsInput = parsePacksFromInput(rawPacksInput, languages, packsInputCombines); const packsInput = parsePacksFromInput(rawPacksInput, languages, packsInputCombines);
const queriesInputCombines = shouldCombine(rawQueriesInput); const queriesInputCombines = shouldCombine(rawQueriesInput);
const queriesInput = parseQueriesFromInput(rawQueriesInput, queriesInputCombines); 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 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 { return {
packsInputCombines, packsInputCombines,
packsInput: packsInput?.[languages[0]], packsInput: packsInput?.[languages[0]],
queriesInput, queriesInput,
queriesInputCombines, queriesInputCombines,
qualityQueriesInput, qualityQueriesInput,
extraQueryExclusions, extraQueryExclusions: [],
overlayDatabaseMode, overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching, useOverlayDatabaseCaching: false,
}; };
} }
function parseQueriesFromInput(rawQueriesInput, queriesInputCombines) { function parseQueriesFromInput(rawQueriesInput, queriesInputCombines) {
@@ -368,6 +330,64 @@ function parseQueriesFromInput(rawQueriesInput, queriesInputCombines) {
} }
return trimmedInput.split(",").map((query) => ({ uses: query.trim() })); 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. * 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 * @returns An object containing the overlay database mode and whether the
* action should perform overlay-base database caching. * 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 overlayDatabaseMode = overlay_database_utils_1.OverlayDatabaseMode.None;
let useOverlayDatabaseCaching = false; let useOverlayDatabaseCaching = false;
const modeEnv = process.env.CODEQL_OVERLAY_DATABASE_MODE; 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} ` + logger.info(`Setting overlay database mode to ${overlayDatabaseMode} ` +
"from the CODEQL_OVERLAY_DATABASE_MODE environment variable."); "from the CODEQL_OVERLAY_DATABASE_MODE environment variable.");
} }
else if ( else if (await 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.
["github", "dsp-testing"].includes(repository.owner) &&
(await features.getValue(feature_flags_1.Feature.OverlayAnalysis, codeql))) {
if ((0, actions_util_1.isAnalyzingPullRequest)()) { if ((0, actions_util_1.isAnalyzingPullRequest)()) {
overlayDatabaseMode = overlay_database_utils_1.OverlayDatabaseMode.Overlay; overlayDatabaseMode = overlay_database_utils_1.OverlayDatabaseMode.Overlay;
useOverlayDatabaseCaching = true; useOverlayDatabaseCaching = true;
@@ -586,7 +602,6 @@ function userConfigFromActionPath(tempDir) {
* a default config. The parsed config is then stored to a known location. * a default config. The parsed config is then stored to a known location.
*/ */
async function initConfig(inputs) { async function initConfig(inputs) {
let config;
const { logger, tempDir } = inputs; const { logger, tempDir } = inputs;
// if configInput is set, it takes precedence over configFile // if configInput is set, it takes precedence over configFile
if (inputs.configInput) { if (inputs.configInput) {
@@ -597,14 +612,31 @@ async function initConfig(inputs) {
fs.writeFileSync(inputs.configFile, inputs.configInput); fs.writeFileSync(inputs.configFile, inputs.configInput);
logger.debug(`Using config from action input: ${inputs.configFile}`); logger.debug(`Using config from action input: ${inputs.configFile}`);
} }
// If no config file was provided create an empty one let userConfig = {};
if (!inputs.configFile) { if (!inputs.configFile) {
logger.debug("No configuration file was provided"); logger.debug("No configuration file was provided");
config = await getDefaultConfig(inputs);
} }
else { else {
// Convince the type checker that inputs.configFile is defined. logger.debug(`Using configuration file: ${inputs.configFile}`);
config = await loadConfig({ ...inputs, configFile: 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 // Save the config so we can easily access it again in the future
await saveConfig(config, logger); await saveConfig(config, logger);
@@ -807,4 +839,56 @@ async function parseBuildModeInput(input, languages, features, logger) {
} }
return input; 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 //# sourceMappingURL=config-utils.js.map

File diff suppressed because one or more lines are too long

237
lib/config-utils.test.js generated
View File

@@ -629,9 +629,7 @@ const packSpecPrettyPrintingMacro = ava_1.default.macro({
const mockLogger = (0, logging_1.getRunnerLogger)(true); const mockLogger = (0, logging_1.getRunnerLogger)(true);
const calculateAugmentationMacro = ava_1.default.macro({ const calculateAugmentationMacro = ava_1.default.macro({
exec: async (t, _title, rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages, expectedAugmentationProperties) => { exec: async (t, _title, rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages, expectedAugmentationProperties) => {
const actualAugmentationProperties = await configUtils.calculateAugmentation((0, codeql_1.getCachedCodeQL)(), { owner: "github", repo: "repo" }, (0, testing_utils_1.createFeatures)([]), rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages, "", // sourceRoot const actualAugmentationProperties = await configUtils.calculateAugmentation(rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages);
undefined, // buildMode
mockLogger);
t.deepEqual(actualAugmentationProperties, expectedAugmentationProperties); t.deepEqual(actualAugmentationProperties, expectedAugmentationProperties);
}, },
title: (_, title) => `Calculate Augmentation: ${title}`, title: (_, title) => `Calculate Augmentation: ${title}`,
@@ -678,9 +676,7 @@ const calculateAugmentationMacro = ava_1.default.macro({
}); });
const calculateAugmentationErrorMacro = ava_1.default.macro({ const calculateAugmentationErrorMacro = ava_1.default.macro({
exec: async (t, _title, rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages, expectedError) => { exec: async (t, _title, rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages, expectedError) => {
await t.throwsAsync(() => configUtils.calculateAugmentation((0, codeql_1.getCachedCodeQL)(), { owner: "github", repo: "repo" }, (0, testing_utils_1.createFeatures)([]), rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages, "", // sourceRoot await t.throwsAsync(() => configUtils.calculateAugmentation(rawPacksInput, rawQueriesInput, rawQualityQueriesInput, languages), { message: expectedError });
undefined, // buildMode
mockLogger), { message: expectedError });
}, },
title: (_, title) => `Calculate Augmentation Error: ${title}`, title: (_, title) => `Calculate Augmentation Error: ${title}`,
}); });
@@ -834,7 +830,7 @@ for (const { displayName, language, feature } of [
} }
const defaultOverlayDatabaseModeTestSetup = { const defaultOverlayDatabaseModeTestSetup = {
overlayDatabaseEnvVar: undefined, overlayDatabaseEnvVar: undefined,
isFeatureEnabled: false, features: [],
isPullRequest: false, isPullRequest: false,
isDefaultBranch: false, isDefaultBranch: false,
repositoryOwner: "github", repositoryOwner: "github",
@@ -842,6 +838,7 @@ const defaultOverlayDatabaseModeTestSetup = {
languages: [languages_1.Language.javascript], languages: [languages_1.Language.javascript],
codeqlVersion: "2.21.0", codeqlVersion: "2.21.0",
gitRoot: "/some/git/root", gitRoot: "/some/git/root",
codeScanningConfig: {},
}; };
const getOverlayDatabaseModeMacro = ava_1.default.macro({ const getOverlayDatabaseModeMacro = ava_1.default.macro({
exec: async (t, _title, setupOverrides, expected) => { exec: async (t, _title, setupOverrides, expected) => {
@@ -862,7 +859,7 @@ const getOverlayDatabaseModeMacro = ava_1.default.macro({
setup.overlayDatabaseEnvVar; setup.overlayDatabaseEnvVar;
} }
// Mock feature flags // Mock feature flags
const features = (0, testing_utils_1.createFeatures)(setup.isFeatureEnabled ? [feature_flags_1.Feature.OverlayAnalysis] : []); const features = (0, testing_utils_1.createFeatures)(setup.features);
// Mock isAnalyzingPullRequest function // Mock isAnalyzingPullRequest function
sinon sinon
.stub(actionsUtil, "isAnalyzingPullRequest") .stub(actionsUtil, "isAnalyzingPullRequest")
@@ -883,7 +880,7 @@ const getOverlayDatabaseModeMacro = ava_1.default.macro({
.stub(gitUtils, "isAnalyzingDefaultBranch") .stub(gitUtils, "isAnalyzingDefaultBranch")
.resolves(setup.isDefaultBranch); .resolves(setup.isDefaultBranch);
const result = await configUtils.getOverlayDatabaseMode(codeql, repository, features, setup.languages, tempDir, // sourceRoot const result = await configUtils.getOverlayDatabaseMode(codeql, repository, features, setup.languages, tempDir, // sourceRoot
setup.buildMode, logger); setup.buildMode, setup.codeScanningConfig, logger);
t.deepEqual(result, expected); t.deepEqual(result, expected);
} }
finally { finally {
@@ -919,32 +916,227 @@ const getOverlayDatabaseModeMacro = ava_1.default.macro({
useOverlayDatabaseCaching: false, useOverlayDatabaseCaching: false,
}); });
(0, ava_1.default)(getOverlayDatabaseModeMacro, "Ignore feature flag when analyzing non-default branch", { (0, ava_1.default)(getOverlayDatabaseModeMacro, "Ignore feature flag when analyzing non-default branch", {
isFeatureEnabled: true, languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis, feature_flags_1.Feature.OverlayAnalysisJavascript],
}, { }, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None, overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false, useOverlayDatabaseCaching: false,
}); });
(0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay-base database on default branch when feature enabled", { (0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay-base database on default branch when feature enabled", {
isFeatureEnabled: true, languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis, feature_flags_1.Feature.OverlayAnalysisJavascript],
isDefaultBranch: true, isDefaultBranch: true,
}, { }, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.OverlayBase, overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.OverlayBase,
useOverlayDatabaseCaching: true, useOverlayDatabaseCaching: true,
}); });
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay-base database on default branch when feature disabled", { (0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay-base database on default branch when feature enabled with custom analysis", {
languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis, feature_flags_1.Feature.OverlayAnalysisJavascript],
codeScanningConfig: {
packs: ["some-custom-pack@1.0.0"],
},
isDefaultBranch: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.OverlayBase,
useOverlayDatabaseCaching: true,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay-base database on default branch when code-scanning feature enabled", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
isDefaultBranch: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.OverlayBase,
useOverlayDatabaseCaching: true,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay-base database on default branch when code-scanning feature enabled with disable-default-queries", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
codeScanningConfig: {
"disable-default-queries": true,
},
isDefaultBranch: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay-base database on default branch when code-scanning feature enabled with packs", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
codeScanningConfig: {
packs: ["some-custom-pack@1.0.0"],
},
isDefaultBranch: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay-base database on default branch when code-scanning feature enabled with queries", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
codeScanningConfig: {
queries: [{ uses: "some-query.ql" }],
},
isDefaultBranch: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay-base database on default branch when code-scanning feature enabled with query-filters", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
codeScanningConfig: {
"query-filters": [{ include: { "security-severity": "high" } }],
},
isDefaultBranch: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay-base database on default branch when only language-specific feature enabled", {
languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysisJavascript],
isDefaultBranch: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay-base database on default branch when only code-scanning feature enabled", {
languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript],
isDefaultBranch: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay-base database on default branch when language-specific feature disabled", {
languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis],
isDefaultBranch: true, isDefaultBranch: true,
}, { }, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None, overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false, useOverlayDatabaseCaching: false,
}); });
(0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay analysis on PR when feature enabled", { (0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay analysis on PR when feature enabled", {
isFeatureEnabled: true, languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis, feature_flags_1.Feature.OverlayAnalysisJavascript],
isPullRequest: true, isPullRequest: true,
}, { }, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.Overlay, overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.Overlay,
useOverlayDatabaseCaching: true, useOverlayDatabaseCaching: true,
}); });
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay analysis on PR when feature disabled", { (0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay analysis on PR when feature enabled with custom analysis", {
languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis, feature_flags_1.Feature.OverlayAnalysisJavascript],
codeScanningConfig: {
packs: ["some-custom-pack@1.0.0"],
},
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.Overlay,
useOverlayDatabaseCaching: true,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay analysis on PR when code-scanning feature enabled", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.Overlay,
useOverlayDatabaseCaching: true,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay analysis on PR when code-scanning feature enabled with disable-default-queries", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
codeScanningConfig: {
"disable-default-queries": true,
},
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay analysis on PR when code-scanning feature enabled with packs", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
codeScanningConfig: {
packs: ["some-custom-pack@1.0.0"],
},
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay analysis on PR when code-scanning feature enabled with queries", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
codeScanningConfig: {
queries: [{ uses: "some-query.ql" }],
},
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay analysis on PR when code-scanning feature enabled with query-filters", {
languages: [languages_1.Language.javascript],
features: [
feature_flags_1.Feature.OverlayAnalysis,
feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript,
],
codeScanningConfig: {
"query-filters": [{ include: { "security-severity": "high" } }],
},
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay analysis on PR when only language-specific feature enabled", {
languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysisJavascript],
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay analysis on PR when only code-scanning feature enabled", {
languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysisCodeScanningJavascript],
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay analysis on PR when language-specific feature disabled", {
languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis],
isPullRequest: true, isPullRequest: true,
}, { }, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None, overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
@@ -965,7 +1157,8 @@ const getOverlayDatabaseModeMacro = ava_1.default.macro({
useOverlayDatabaseCaching: false, useOverlayDatabaseCaching: false,
}); });
(0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay PR analysis by feature flag for dsp-testing", { (0, ava_1.default)(getOverlayDatabaseModeMacro, "Overlay PR analysis by feature flag for dsp-testing", {
isFeatureEnabled: true, languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis, feature_flags_1.Feature.OverlayAnalysisJavascript],
isPullRequest: true, isPullRequest: true,
repositoryOwner: "dsp-testing", repositoryOwner: "dsp-testing",
}, { }, {
@@ -973,7 +1166,8 @@ const getOverlayDatabaseModeMacro = ava_1.default.macro({
useOverlayDatabaseCaching: true, useOverlayDatabaseCaching: true,
}); });
(0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay PR analysis by feature flag for other-org", { (0, ava_1.default)(getOverlayDatabaseModeMacro, "No overlay PR analysis by feature flag for other-org", {
isFeatureEnabled: true, languages: [languages_1.Language.javascript],
features: [feature_flags_1.Feature.OverlayAnalysis, feature_flags_1.Feature.OverlayAnalysisJavascript],
isPullRequest: true, isPullRequest: true,
repositoryOwner: "other-org", repositoryOwner: "other-org",
}, { }, {
@@ -1010,4 +1204,15 @@ const getOverlayDatabaseModeMacro = ava_1.default.macro({
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None, overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false, useOverlayDatabaseCaching: false,
}); });
// Exercise language-specific overlay analysis features code paths
for (const language in languages_1.Language) {
(0, ava_1.default)(getOverlayDatabaseModeMacro, `Check default overlay analysis feature for ${language}`, {
languages: [language],
features: [feature_flags_1.Feature.OverlayAnalysis],
isPullRequest: true,
}, {
overlayDatabaseMode: overlay_database_utils_1.OverlayDatabaseMode.None,
useOverlayDatabaseCaching: false,
});
}
//# sourceMappingURL=config-utils.test.js.map //# sourceMappingURL=config-utils.test.js.map

File diff suppressed because one or more lines are too long

144
lib/feature-flags.js generated
View File

@@ -69,6 +69,26 @@ var Feature;
Feature["ExportDiagnosticsEnabled"] = "export_diagnostics_enabled"; Feature["ExportDiagnosticsEnabled"] = "export_diagnostics_enabled";
Feature["ExtractToToolcache"] = "extract_to_toolcache"; Feature["ExtractToToolcache"] = "extract_to_toolcache";
Feature["OverlayAnalysis"] = "overlay_analysis"; Feature["OverlayAnalysis"] = "overlay_analysis";
Feature["OverlayAnalysisActions"] = "overlay_analysis_actions";
Feature["OverlayAnalysisCodeScanningActions"] = "overlay_analysis_code_scanning_actions";
Feature["OverlayAnalysisCodeScanningCpp"] = "overlay_analysis_code_scanning_cpp";
Feature["OverlayAnalysisCodeScanningCsharp"] = "overlay_analysis_code_scanning_csharp";
Feature["OverlayAnalysisCodeScanningGo"] = "overlay_analysis_code_scanning_go";
Feature["OverlayAnalysisCodeScanningJava"] = "overlay_analysis_code_scanning_java";
Feature["OverlayAnalysisCodeScanningJavascript"] = "overlay_analysis_code_scanning_javascript";
Feature["OverlayAnalysisCodeScanningPython"] = "overlay_analysis_code_scanning_python";
Feature["OverlayAnalysisCodeScanningRuby"] = "overlay_analysis_code_scanning_ruby";
Feature["OverlayAnalysisCodeScanningRust"] = "overlay_analysis_code_scanning_rust";
Feature["OverlayAnalysisCodeScanningSwift"] = "overlay_analysis_code_scanning_swift";
Feature["OverlayAnalysisCpp"] = "overlay_analysis_cpp";
Feature["OverlayAnalysisCsharp"] = "overlay_analysis_csharp";
Feature["OverlayAnalysisGo"] = "overlay_analysis_go";
Feature["OverlayAnalysisJava"] = "overlay_analysis_java";
Feature["OverlayAnalysisJavascript"] = "overlay_analysis_javascript";
Feature["OverlayAnalysisPython"] = "overlay_analysis_python";
Feature["OverlayAnalysisRuby"] = "overlay_analysis_ruby";
Feature["OverlayAnalysisRust"] = "overlay_analysis_rust";
Feature["OverlayAnalysisSwift"] = "overlay_analysis_swift";
Feature["PythonDefaultIsToNotExtractStdlib"] = "python_default_is_to_not_extract_stdlib"; Feature["PythonDefaultIsToNotExtractStdlib"] = "python_default_is_to_not_extract_stdlib";
Feature["QaTelemetryEnabled"] = "qa_telemetry_enabled"; Feature["QaTelemetryEnabled"] = "qa_telemetry_enabled";
Feature["RustAnalysis"] = "rust_analysis"; Feature["RustAnalysis"] = "rust_analysis";
@@ -139,6 +159,106 @@ exports.featureConfig = {
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS", envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS",
minimumVersion: overlay_database_utils_1.CODEQL_OVERLAY_MINIMUM_VERSION, minimumVersion: overlay_database_utils_1.CODEQL_OVERLAY_MINIMUM_VERSION,
}, },
[Feature.OverlayAnalysisActions]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_ACTIONS",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningActions]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_ACTIONS",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningCpp]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_CPP",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningCsharp]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_CSHARP",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningGo]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_GO",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningJava]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_JAVA",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningJavascript]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_JAVASCRIPT",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningPython]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_PYTHON",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningRuby]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_RUBY",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningRust]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_RUST",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCodeScanningSwift]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_SWIFT",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCpp]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CPP",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisCsharp]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_CSHARP",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisGo]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_GO",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisJava]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_JAVA",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisJavascript]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_JAVASCRIPT",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisPython]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_PYTHON",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisRuby]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_RUBY",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisRust]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_RUST",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisSwift]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_SWIFT",
minimumVersion: undefined,
},
[Feature.PythonDefaultIsToNotExtractStdlib]: { [Feature.PythonDefaultIsToNotExtractStdlib]: {
defaultValue: false, defaultValue: false,
envVar: "CODEQL_ACTION_DISABLE_PYTHON_STANDARD_LIBRARY_EXTRACTION", envVar: "CODEQL_ACTION_DISABLE_PYTHON_STANDARD_LIBRARY_EXTRACTION",
@@ -370,14 +490,22 @@ class GitHubFeatureFlags {
try { try {
const featuresToRequest = Object.entries(exports.featureConfig) const featuresToRequest = Object.entries(exports.featureConfig)
.filter(([, config]) => !config.legacyApi) .filter(([, config]) => !config.legacyApi)
.map(([f]) => f) .map(([f]) => f);
.join(","); const FEATURES_PER_REQUEST = 25;
const response = await (0, api_client_1.getApiClient)().request("GET /repos/:owner/:repo/code-scanning/codeql-action/features", { const featureChunks = [];
owner: this.repositoryNwo.owner, while (featuresToRequest.length > 0) {
repo: this.repositoryNwo.repo, featureChunks.push(featuresToRequest.splice(0, FEATURES_PER_REQUEST));
features: featuresToRequest, }
}); let remoteFlags = {};
const remoteFlags = response.data; for (const chunk of featureChunks) {
const response = await (0, api_client_1.getApiClient)().request("GET /repos/:owner/:repo/code-scanning/codeql-action/features", {
owner: this.repositoryNwo.owner,
repo: this.repositoryNwo.repo,
features: chunk.join(","),
});
const chunkFlags = response.data;
remoteFlags = { ...remoteFlags, ...chunkFlags };
}
this.logger.debug("Loaded the following default values for the feature flags from the Code Scanning API:"); this.logger.debug("Loaded the following default values for the feature flags from the Code Scanning API:");
for (const [feature, value] of Object.entries(remoteFlags).sort(([nameA], [nameB]) => nameA.localeCompare(nameB))) { for (const [feature, value] of Object.entries(remoteFlags).sort(([nameA], [nameB]) => nameA.localeCompare(nameB))) {
this.logger.debug(` ${feature}: ${value}`); this.logger.debug(` ${feature}: ${value}`);

File diff suppressed because one or more lines are too long

View File

@@ -36,7 +36,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.initializeFeatures = initializeFeatures;
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
const path = __importStar(require("path")); const path = __importStar(require("path"));
const ava_1 = __importDefault(require("ava")); const ava_1 = __importDefault(require("ava"));
@@ -68,7 +67,7 @@ const testRepositoryNwo = (0, repository_1.parseRepositoryNwo)("github/example")
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const loggedMessages = []; const loggedMessages = [];
const features = setUpFeatureFlagTests(tmpDir, (0, testing_utils_1.getRecordingLogger)(loggedMessages), { type: util_1.GitHubVariant.GHE_DOTCOM }); const features = setUpFeatureFlagTests(tmpDir, (0, testing_utils_1.getRecordingLogger)(loggedMessages), { type: util_1.GitHubVariant.GHE_DOTCOM });
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, initializeFeatures(true)); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, (0, testing_utils_1.initializeFeatures)(true));
for (const feature of Object.values(feature_flags_1.Feature)) { for (const feature of Object.values(feature_flags_1.Feature)) {
// Ensure we have gotten a response value back from the Mock API // Ensure we have gotten a response value back from the Mock API
t.assert(await features.getValue(feature, includeCodeQlIfRequired(feature))); t.assert(await features.getValue(feature, includeCodeQlIfRequired(feature)));
@@ -103,6 +102,24 @@ const testRepositoryNwo = (0, repository_1.parseRepositoryNwo)("github/example")
assertAllFeaturesUndefinedInApi(t, loggedMessages); assertAllFeaturesUndefinedInApi(t, loggedMessages);
}); });
}); });
(0, ava_1.default)("Include no more than 25 features in each API request", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir);
(0, testing_utils_1.stubFeatureFlagApiEndpoint)((request) => {
const requestedFeatures = request.features.split(",");
return {
status: requestedFeatures.length <= 25 ? 200 : 400,
messageIfError: "Can request a maximum of 25 features.",
data: {},
};
});
// We only need to call getValue once, and it does not matter which feature
// we ask for. Under the hood, the features library will request all features
// from the API.
const feature = Object.values(feature_flags_1.Feature)[0];
await t.notThrowsAsync(async () => features.getValue(feature, includeCodeQlIfRequired(feature)));
});
});
(0, ava_1.default)("Feature flags exception is propagated if the API request errors", async (t) => { (0, ava_1.default)("Feature flags exception is propagated if the API request errors", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
@@ -135,7 +152,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)(`Only feature '${feature}' is enabled if the associated environment variable is true. Others disabled.`, async (t) => { (0, ava_1.default)(`Only feature '${feature}' is enabled if the associated environment variable is true. Others disabled.`, async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(false); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(false);
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
// feature should be disabled initially // feature should be disabled initially
t.assert(!(await features.getValue(feature, includeCodeQlIfRequired(feature)))); t.assert(!(await features.getValue(feature, includeCodeQlIfRequired(feature))));
@@ -147,7 +164,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)(`Feature '${feature}' is disabled if the associated environment variable is false, even if enabled in API`, async (t) => { (0, ava_1.default)(`Feature '${feature}' is disabled if the associated environment variable is false, even if enabled in API`, async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
// feature should be enabled initially // feature should be enabled initially
t.assert(await features.getValue(feature, includeCodeQlIfRequired(feature))); t.assert(await features.getValue(feature, includeCodeQlIfRequired(feature)));
@@ -161,7 +178,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)(`Getting feature '${feature} should throw if no codeql is provided`, async (t) => { (0, ava_1.default)(`Getting feature '${feature} should throw if no codeql is provided`, async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
await t.throwsAsync(async () => features.getValue(feature), { await t.throwsAsync(async () => features.getValue(feature), {
message: `Internal error: A ${feature_flags_1.featureConfig[feature].minimumVersion !== undefined message: `Internal error: A ${feature_flags_1.featureConfig[feature].minimumVersion !== undefined
@@ -175,7 +192,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)(`Feature '${feature}' is disabled if the minimum CLI version is below ${feature_flags_1.featureConfig[feature].minimumVersion}`, async (t) => { (0, ava_1.default)(`Feature '${feature}' is disabled if the minimum CLI version is below ${feature_flags_1.featureConfig[feature].minimumVersion}`, async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
// feature should be disabled when an old CLI version is set // feature should be disabled when an old CLI version is set
let codeql = (0, testing_utils_1.mockCodeQLVersion)("2.0.0"); let codeql = (0, testing_utils_1.mockCodeQLVersion)("2.0.0");
@@ -199,7 +216,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)(`Feature '${feature}' is disabled if the required tools feature is not enabled`, async (t) => { (0, ava_1.default)(`Feature '${feature}' is disabled if the required tools feature is not enabled`, async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
// feature should be disabled when the required tools feature is not enabled // feature should be disabled when the required tools feature is not enabled
let codeql = (0, testing_utils_1.mockCodeQLVersion)("2.0.0"); let codeql = (0, testing_utils_1.mockCodeQLVersion)("2.0.0");
@@ -225,7 +242,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)("Feature flags are saved to disk", async (t) => { (0, ava_1.default)("Feature flags are saved to disk", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
const cachedFeatureFlags = path.join(tmpDir, feature_flags_1.FEATURE_FLAGS_FILE_NAME); const cachedFeatureFlags = path.join(tmpDir, feature_flags_1.FEATURE_FLAGS_FILE_NAME);
t.false(fs.existsSync(cachedFeatureFlags), "Feature flag cached file should not exist before getting feature flags"); t.false(fs.existsSync(cachedFeatureFlags), "Feature flag cached file should not exist before getting feature flags");
@@ -244,7 +261,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)("Environment variable can override feature flag cache", async (t) => { (0, ava_1.default)("Environment variable can override feature flag cache", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
const cachedFeatureFlags = path.join(tmpDir, feature_flags_1.FEATURE_FLAGS_FILE_NAME); const cachedFeatureFlags = path.join(tmpDir, feature_flags_1.FEATURE_FLAGS_FILE_NAME);
t.true(await features.getValue(feature_flags_1.Feature.QaTelemetryEnabled, includeCodeQlIfRequired(feature_flags_1.Feature.QaTelemetryEnabled)), "Feature flag should be enabled initially"); t.true(await features.getValue(feature_flags_1.Feature.QaTelemetryEnabled, includeCodeQlIfRequired(feature_flags_1.Feature.QaTelemetryEnabled)), "Feature flag should be enabled initially");
@@ -266,7 +283,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)("selects CLI v2.20.1 on Dotcom when feature flags enable v2.20.0 and v2.20.1", async (t) => { (0, ava_1.default)("selects CLI v2.20.1 on Dotcom when feature flags enable v2.20.0 and v2.20.1", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true; expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
expectedFeatureEnablement["default_codeql_version_2_20_1_enabled"] = true; expectedFeatureEnablement["default_codeql_version_2_20_1_enabled"] = true;
expectedFeatureEnablement["default_codeql_version_2_20_2_enabled"] = false; expectedFeatureEnablement["default_codeql_version_2_20_2_enabled"] = false;
@@ -285,7 +302,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)("includes tag name", async (t) => { (0, ava_1.default)("includes tag name", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true; expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
const defaultCliVersion = await features.getDefaultCliVersion(util_1.GitHubVariant.DOTCOM); const defaultCliVersion = await features.getDefaultCliVersion(util_1.GitHubVariant.DOTCOM);
@@ -299,7 +316,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
(0, ava_1.default)(`selects CLI from defaults.json on Dotcom when no default version feature flags are enabled`, async (t) => { (0, ava_1.default)(`selects CLI from defaults.json on Dotcom when no default version feature flags are enabled`, async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const features = setUpFeatureFlagTests(tmpDir); const features = setUpFeatureFlagTests(tmpDir);
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement); (0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
const defaultCliVersion = await features.getDefaultCliVersion(util_1.GitHubVariant.DOTCOM); const defaultCliVersion = await features.getDefaultCliVersion(util_1.GitHubVariant.DOTCOM);
t.deepEqual(defaultCliVersion, { t.deepEqual(defaultCliVersion, {
@@ -313,7 +330,7 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
const loggedMessages = []; const loggedMessages = [];
const features = setUpFeatureFlagTests(tmpDir, (0, testing_utils_1.getRecordingLogger)(loggedMessages)); const features = setUpFeatureFlagTests(tmpDir, (0, testing_utils_1.getRecordingLogger)(loggedMessages));
const expectedFeatureEnablement = initializeFeatures(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true; expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
expectedFeatureEnablement["default_codeql_version_2_20_1_enabled"] = true; expectedFeatureEnablement["default_codeql_version_2_20_1_enabled"] = true;
expectedFeatureEnablement["default_codeql_version_2_20_invalid_enabled"] = expectedFeatureEnablement["default_codeql_version_2_20_invalid_enabled"] =
@@ -358,12 +375,6 @@ function assertAllFeaturesUndefinedInApi(t, loggedMessages) {
v.message.includes("undefined in API response")) !== undefined); v.message.includes("undefined in API response")) !== undefined);
} }
} }
function initializeFeatures(initialValue) {
return Object.keys(feature_flags_1.featureConfig).reduce((features, key) => {
features[key] = initialValue;
return features;
}, {});
}
function setUpFeatureFlagTests(tmpDir, logger = (0, logging_1.getRunnerLogger)(true), gitHubVersion = { type: util_1.GitHubVariant.DOTCOM }) { function setUpFeatureFlagTests(tmpDir, logger = (0, logging_1.getRunnerLogger)(true), gitHubVersion = { type: util_1.GitHubVariant.DOTCOM }) {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
return new feature_flags_1.Features(gitHubVersion, testRepositoryNwo, tmpDir, logger); return new feature_flags_1.Features(gitHubVersion, testRepositoryNwo, tmpDir, logger);

File diff suppressed because one or more lines are too long

View File

@@ -40,14 +40,13 @@ const path = __importStar(require("path"));
const ava_1 = __importDefault(require("ava")); const ava_1 = __importDefault(require("ava"));
const sinon = __importStar(require("sinon")); const sinon = __importStar(require("sinon"));
const actionsUtil = __importStar(require("./actions-util")); const actionsUtil = __importStar(require("./actions-util"));
const feature_flags_test_1 = require("./feature-flags.test");
const logging_1 = require("./logging"); const logging_1 = require("./logging");
const setupCodeql = __importStar(require("./setup-codeql")); const setupCodeql = __importStar(require("./setup-codeql"));
const testing_utils_1 = require("./testing-utils"); const testing_utils_1 = require("./testing-utils");
const util_1 = require("./util"); const util_1 = require("./util");
(0, testing_utils_1.setupTests)(ava_1.default); (0, testing_utils_1.setupTests)(ava_1.default);
// TODO: Remove when when we no longer need to pass in features (https://github.com/github/codeql-action/issues/2600) // TODO: Remove when when we no longer need to pass in features (https://github.com/github/codeql-action/issues/2600)
const expectedFeatureEnablement = (0, feature_flags_test_1.initializeFeatures)(true); const expectedFeatureEnablement = (0, testing_utils_1.initializeFeatures)(true);
expectedFeatureEnablement.getValue = function (feature) { expectedFeatureEnablement.getValue = function (feature) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return // eslint-disable-next-line @typescript-eslint/no-unsafe-return
return expectedFeatureEnablement[feature]; return expectedFeatureEnablement[feature];

File diff suppressed because one or more lines are too long

43
lib/testing-utils.js generated
View File

@@ -41,9 +41,11 @@ exports.setupTests = setupTests;
exports.setupActionsVars = setupActionsVars; exports.setupActionsVars = setupActionsVars;
exports.getRecordingLogger = getRecordingLogger; exports.getRecordingLogger = getRecordingLogger;
exports.mockFeatureFlagApiEndpoint = mockFeatureFlagApiEndpoint; exports.mockFeatureFlagApiEndpoint = mockFeatureFlagApiEndpoint;
exports.stubFeatureFlagApiEndpoint = stubFeatureFlagApiEndpoint;
exports.mockLanguagesInRepo = mockLanguagesInRepo; exports.mockLanguagesInRepo = mockLanguagesInRepo;
exports.mockCodeQLVersion = mockCodeQLVersion; exports.mockCodeQLVersion = mockCodeQLVersion;
exports.createFeatures = createFeatures; exports.createFeatures = createFeatures;
exports.initializeFeatures = initializeFeatures;
exports.mockBundleDownloadApi = mockBundleDownloadApi; exports.mockBundleDownloadApi = mockBundleDownloadApi;
exports.createTestConfig = createTestConfig; exports.createTestConfig = createTestConfig;
const node_util_1 = require("node:util"); const node_util_1 = require("node:util");
@@ -54,6 +56,7 @@ const sinon = __importStar(require("sinon"));
const apiClient = __importStar(require("./api-client")); const apiClient = __importStar(require("./api-client"));
const codeql = __importStar(require("./codeql")); const codeql = __importStar(require("./codeql"));
const defaults = __importStar(require("./defaults.json")); const defaults = __importStar(require("./defaults.json"));
const feature_flags_1 = require("./feature-flags");
const util_1 = require("./util"); const util_1 = require("./util");
exports.SAMPLE_DOTCOM_API_DETAILS = { exports.SAMPLE_DOTCOM_API_DETAILS = {
auth: "token", auth: "token",
@@ -172,21 +175,32 @@ function getRecordingLogger(messages) {
} }
/** Mock the HTTP request to the feature flags enablement API endpoint. */ /** Mock the HTTP request to the feature flags enablement API endpoint. */
function mockFeatureFlagApiEndpoint(responseStatusCode, response) { function mockFeatureFlagApiEndpoint(responseStatusCode, response) {
stubFeatureFlagApiEndpoint(() => ({
status: responseStatusCode,
messageIfError: "some error message",
data: response,
}));
}
/** Stub the HTTP request to the feature flags enablement API endpoint. */
function stubFeatureFlagApiEndpoint(responseFunction) {
// Passing an auth token is required, so we just use a dummy value // Passing an auth token is required, so we just use a dummy value
const client = github.getOctokit("123"); const client = github.getOctokit("123");
const requestSpy = sinon.stub(client, "request"); const requestSpy = sinon.stub(client, "request");
const optInSpy = requestSpy.withArgs("GET /repos/:owner/:repo/code-scanning/codeql-action/features"); const optInSpy = requestSpy.withArgs("GET /repos/:owner/:repo/code-scanning/codeql-action/features");
if (responseStatusCode < 300) { optInSpy.callsFake((_route, params) => {
optInSpy.resolves({ const response = responseFunction(params);
status: responseStatusCode, if (response.status < 300) {
data: response, return Promise.resolve({
headers: {}, status: response.status,
url: "GET /repos/:owner/:repo/code-scanning/codeql-action/features", data: response.data,
}); headers: {},
} url: "GET /repos/:owner/:repo/code-scanning/codeql-action/features",
else { });
optInSpy.throws(new util_1.HTTPError("some error message", responseStatusCode)); }
} else {
throw new util_1.HTTPError(response.messageIfError || "default stub error message", response.status);
}
});
sinon.stub(apiClient, "getApiClient").value(() => client); sinon.stub(apiClient, "getApiClient").value(() => client);
} }
function mockLanguagesInRepo(languages) { function mockLanguagesInRepo(languages) {
@@ -240,6 +254,12 @@ function createFeatures(enabledFeatures) {
}, },
}; };
} }
function initializeFeatures(initialValue) {
return Object.keys(feature_flags_1.featureConfig).reduce((features, key) => {
features[key] = initialValue;
return features;
}, {});
}
/** /**
* Mocks the API for downloading the bundle tagged `tagName`. * Mocks the API for downloading the bundle tagged `tagName`.
* *
@@ -282,6 +302,7 @@ function createTestConfig(overrides) {
augmentationProperties: { augmentationProperties: {
packsInputCombines: false, packsInputCombines: false,
queriesInputCombines: false, queriesInputCombines: false,
extraQueryExclusions: [],
}, },
trapCaches: {}, trapCaches: {},
trapCacheDownloadTime: 0, trapCacheDownloadTime: 0,

File diff suppressed because one or more lines are too long