diff --git a/src/codeql.ts b/src/codeql.ts index 0cc917c22..7d82af72a 100644 --- a/src/codeql.ts +++ b/src/codeql.ts @@ -13,7 +13,7 @@ import { } from "./actions-util"; import * as api from "./api-client"; import { CliError, wrapCliConfigurationError } from "./cli-errors"; -import { type Config } from "./config-utils"; +import { generateCodeScanningConfig, type Config } from "./config-utils"; import { DocUrl } from "./doc-url"; import { EnvVar } from "./environment"; import { @@ -35,7 +35,7 @@ import { ToolsDownloadStatusReport } from "./tools-download"; import { ToolsFeature, isSupportedToolsFeature } from "./tools-features"; import { shouldEnableIndirectTracing } from "./tracer-config"; import * as util from "./util"; -import { BuildMode, cloneObject, getErrorMessage } from "./util"; +import { BuildMode, getErrorMessage } from "./util"; type Options = Array; @@ -574,7 +574,7 @@ export async function getCodeQLForCmd( extraArgs.push(`--trace-process-name=${processName}`); } - const codeScanningConfigFile = await generateCodeScanningConfig( + const codeScanningConfigFile = await writeCodeScanningConfigFile( config, logger, ); @@ -1217,66 +1217,15 @@ async function runCli( * @param config The configuration to use. * @returns the path to the generated user configuration file. */ -async function generateCodeScanningConfig( +async function writeCodeScanningConfigFile( config: Config, logger: Logger, ): Promise { const codeScanningConfigFile = getGeneratedCodeScanningConfigPath(config); - - // make a copy so we can modify it - const augmentedConfig = 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"]; - } + const augmentedConfig = generateCodeScanningConfig( + config.originalUserInput, + config.augmentationProperties, + ); logger.info( `Writing augmented user configuration file to ${codeScanningConfigFile}`, diff --git a/src/config-utils.ts b/src/config-utils.ts index 675dd1ea5..c9ef95bbb 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -8,7 +8,7 @@ import * as semver from "semver"; import { isAnalyzingPullRequest } from "./actions-util"; import * as api from "./api-client"; import { CachingKind, getCachingKind } from "./caching-utils"; -import { CodeQL } from "./codeql"; +import { type CodeQL } from "./codeql"; import { shouldPerformDiffInformedAnalysis } from "./diff-informed-analysis-utils"; import { Feature, FeatureEnablement } from "./feature-flags"; import { getGitRoot, isAnalyzingDefaultBranch } from "./git-utils"; @@ -26,6 +26,7 @@ import { ConfigurationError, BuildMode, codeQlVersionAtLeast, + cloneObject, } from "./util"; // Property names from the user-supplied config file. @@ -1313,3 +1314,64 @@ export async function parseBuildModeInput( } return input as BuildMode; } + +export function generateCodeScanningConfig( + originalUserInput: UserConfig, + augmentationProperties: AugmentationProperties, +): UserConfig { + // make a copy so we can modify it + const augmentedConfig = 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; +} diff --git a/src/trap-caching.ts b/src/trap-caching.ts index 73491a13e..74b3581ff 100644 --- a/src/trap-caching.ts +++ b/src/trap-caching.ts @@ -5,8 +5,8 @@ import * as actionsCache from "@actions/cache"; import * as actionsUtil from "./actions-util"; import * as apiClient from "./api-client"; -import { CodeQL } from "./codeql"; -import type { Config } from "./config-utils"; +import { type CodeQL } from "./codeql"; +import { type Config } from "./config-utils"; import { DocUrl } from "./doc-url"; import { Feature, FeatureEnablement } from "./feature-flags"; import * as gitUtils from "./git-utils";