Merge pull request #1116 from github/aeisenberg/multi-lang-packs

Allow scans with packs for languages not being scanned
This commit is contained in:
Andrew Eisenberg 2022-06-24 16:47:56 -07:00 committed by GitHub
commit 47bcabd3e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 93 additions and 37 deletions

View file

@ -2,6 +2,7 @@
## [UNRELEASED] ## [UNRELEASED]
- CodeQL query packs listed in the `packs` configuration field will be skipped if their target language is not being analyzed in the current Actions job. Previously, this would throw an error. [#1116](https://github.com/github/codeql-action/pull/1116)
- The combination of python2 and poetry is no longer supported. See https://github.com/actions/setup-python/issues/374 for more details. [#1124](https://github.com/github/codeql-action/pull/1124) - The combination of python2 and poetry is no longer supported. See https://github.com/actions/setup-python/issues/374 for more details. [#1124](https://github.com/github/codeql-action/pull/1124)
## 2.1.14 - 22 Jun 2022 ## 2.1.14 - 22 Jun 2022

23
lib/config-utils.js generated
View file

@ -19,7 +19,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result; return result;
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.getConfig = exports.getPathToParsedConfigFile = exports.initConfig = exports.parsePacks = exports.validatePacksSpecification = exports.parsePacksFromConfig = exports.getDefaultConfig = exports.getUnknownLanguagesError = exports.getNoLanguagesError = exports.getConfigFileDirectoryGivenMessage = exports.getConfigFileFormatInvalidMessage = exports.getConfigFileRepoFormatInvalidMessage = exports.getConfigFileDoesNotExistErrorMessage = exports.getConfigFileOutsideWorkspaceErrorMessage = exports.getLocalPathDoesNotExist = exports.getLocalPathOutsideOfRepository = exports.getPacksStrInvalid = exports.getPacksInvalid = exports.getPacksInvalidSplit = exports.getPacksRequireLanguage = exports.getPathsInvalid = exports.getPathsIgnoreInvalid = exports.getQueryUsesInvalid = exports.getQueriesInvalid = exports.getDisableDefaultQueriesInvalid = exports.getNameInvalid = exports.validateAndSanitisePath = void 0; exports.getConfig = exports.getPathToParsedConfigFile = exports.initConfig = exports.parsePacks = exports.validatePacksSpecification = exports.parsePacksFromConfig = exports.getDefaultConfig = exports.getUnknownLanguagesError = exports.getNoLanguagesError = exports.getConfigFileDirectoryGivenMessage = exports.getConfigFileFormatInvalidMessage = exports.getConfigFileRepoFormatInvalidMessage = exports.getConfigFileDoesNotExistErrorMessage = exports.getConfigFileOutsideWorkspaceErrorMessage = exports.getLocalPathDoesNotExist = exports.getLocalPathOutsideOfRepository = exports.getPacksStrInvalid = exports.getPacksInvalid = exports.getPacksInvalidSplit = exports.getPathsInvalid = exports.getPathsIgnoreInvalid = exports.getQueryUsesInvalid = exports.getQueriesInvalid = exports.getDisableDefaultQueriesInvalid = exports.getNameInvalid = exports.validateAndSanitisePath = void 0;
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
const path = __importStar(require("path")); const path = __importStar(require("path"));
const yaml = __importStar(require("js-yaml")); const yaml = __importStar(require("js-yaml"));
@ -306,9 +306,8 @@ function getPathsInvalid(configFile) {
} }
exports.getPathsInvalid = getPathsInvalid; exports.getPathsInvalid = getPathsInvalid;
function getPacksRequireLanguage(lang, configFile) { function getPacksRequireLanguage(lang, configFile) {
return getConfigFilePropertyError(configFile, PACKS_PROPERTY, `has "${lang}", but it is not one of the languages to analyze`); return getConfigFilePropertyError(configFile, PACKS_PROPERTY, `has "${lang}", but it is not a valid language.`);
} }
exports.getPacksRequireLanguage = getPacksRequireLanguage;
function getPacksInvalidSplit(configFile) { function getPacksInvalidSplit(configFile) {
return getConfigFilePropertyError(configFile, PACKS_PROPERTY, "must split packages by language"); return getConfigFilePropertyError(configFile, PACKS_PROPERTY, "must split packages by language");
} }
@ -542,7 +541,7 @@ async function loadConfig(languagesInput, queriesInput, packsInput, configFile,
if (!disableDefaultQueries) { if (!disableDefaultQueries) {
await addDefaultQueries(codeQL, languages, queries); await addDefaultQueries(codeQL, languages, queries);
} }
const packs = parsePacks((_a = parsedYAML[PACKS_PROPERTY]) !== null && _a !== void 0 ? _a : {}, packsInput, languages, configFile); const packs = parsePacks((_a = parsedYAML[PACKS_PROPERTY]) !== null && _a !== void 0 ? _a : {}, packsInput, languages, configFile, logger);
// If queries were provided using `with` in the action configuration, // If queries were provided using `with` in the action configuration,
// they should take precedence over the queries in the config file // they should take precedence over the queries in the config file
// unless they're prefixed with "+", in which case they supplement those // unless they're prefixed with "+", in which case they supplement those
@ -616,7 +615,7 @@ const PACK_IDENTIFIER_PATTERN = (function () {
return new RegExp(`^${component}/${component}$`); return new RegExp(`^${component}/${component}$`);
})(); })();
// Exported for testing // Exported for testing
function parsePacksFromConfig(packsByLanguage, languages, configFile) { function parsePacksFromConfig(packsByLanguage, languages, configFile, logger) {
const packs = {}; const packs = {};
if (Array.isArray(packsByLanguage)) { if (Array.isArray(packsByLanguage)) {
if (languages.length === 1) { if (languages.length === 1) {
@ -636,7 +635,15 @@ function parsePacksFromConfig(packsByLanguage, languages, configFile) {
throw new Error(getPacksInvalid(configFile)); throw new Error(getPacksInvalid(configFile));
} }
if (!languages.includes(lang)) { if (!languages.includes(lang)) {
throw new Error(getPacksRequireLanguage(lang, configFile)); // This particular language is not being analyzed in this run.
if (languages_1.Language[lang]) {
logger.info(`Ignoring packs for ${lang} since this language is not being analyzed in this run.`);
continue;
}
else {
// This language is invalid, probably a misspelling
throw new Error(getPacksRequireLanguage(configFile, lang));
}
} }
packs[lang] = []; packs[lang] = [];
for (const packStr of packsArr) { for (const packStr of packsArr) {
@ -734,9 +741,9 @@ function validatePacksSpecification(packStr, configFile) {
} }
exports.validatePacksSpecification = validatePacksSpecification; exports.validatePacksSpecification = validatePacksSpecification;
// exported for testing // exported for testing
function parsePacks(rawPacksFromConfig, rawPacksInput, languages, configFile) { function parsePacks(rawPacksFromConfig, rawPacksInput, languages, configFile, logger) {
const packsFromInput = parsePacksFromInput(rawPacksInput, languages); const packsFromInput = parsePacksFromInput(rawPacksInput, languages);
const packsFomConfig = parsePacksFromConfig(rawPacksFromConfig, languages, configFile); const packsFomConfig = parsePacksFromConfig(rawPacksFromConfig, languages, configFile, logger);
if (!packsFromInput) { if (!packsFromInput) {
return packsFomConfig; return packsFomConfig;
} }

File diff suppressed because one or more lines are too long

View file

@ -749,14 +749,14 @@ const invalidPaths = ["a/***/b", "a/**b", "a/b**", "**"];
* Test macro for ensuring the packs block is valid * Test macro for ensuring the packs block is valid
*/ */
const parsePacksMacro = ava_1.default.macro({ const parsePacksMacro = ava_1.default.macro({
exec: (t, packsByLanguage, languages, expected) => t.deepEqual(configUtils.parsePacksFromConfig(packsByLanguage, languages, "/a/b"), expected), exec: (t, packsByLanguage, languages, expected) => t.deepEqual(configUtils.parsePacksFromConfig(packsByLanguage, languages, "/a/b", mockLogger), expected),
title: (providedTitle = "") => `Parse Packs: ${providedTitle}`, title: (providedTitle = "") => `Parse Packs: ${providedTitle}`,
}); });
/** /**
* Test macro for testing when the packs block is invalid * Test macro for testing when the packs block is invalid
*/ */
const parsePacksErrorMacro = ava_1.default.macro({ const parsePacksErrorMacro = ava_1.default.macro({
exec: (t, packsByLanguage, languages, expected) => t.throws(() => configUtils.parsePacksFromConfig(packsByLanguage, languages, "/a/b"), { exec: (t, packsByLanguage, languages, expected) => t.throws(() => configUtils.parsePacksFromConfig(packsByLanguage, languages, "/a/b", {}), {
message: expected, message: expected,
}), }),
title: (providedTitle = "") => `Parse Packs Error: ${providedTitle}`, title: (providedTitle = "") => `Parse Packs Error: ${providedTitle}`,
@ -782,6 +782,12 @@ const invalidPackNameMacro = ava_1.default.macro({
[languages_1.Language.cpp]: ["a/b", "c/d@1.2.3"], [languages_1.Language.cpp]: ["a/b", "c/d@1.2.3"],
[languages_1.Language.java]: ["d/e", "f/g@1.2.3"], [languages_1.Language.java]: ["d/e", "f/g@1.2.3"],
}); });
(0, ava_1.default)("two packs with unused language in config", parsePacksMacro, {
[languages_1.Language.cpp]: ["a/b", "c/d@1.2.3"],
[languages_1.Language.java]: ["d/e", "f/g@1.2.3"],
}, [languages_1.Language.cpp, languages_1.Language.csharp], {
[languages_1.Language.cpp]: ["a/b", "c/d@1.2.3"],
});
(0, ava_1.default)("packs with other valid names", parsePacksMacro, [ (0, ava_1.default)("packs with other valid names", parsePacksMacro, [
// ranges are ok // ranges are ok
"c/d@1.0", "c/d@1.0",
@ -814,7 +820,6 @@ const invalidPackNameMacro = ava_1.default.macro({
], ],
}); });
(0, ava_1.default)("no language", parsePacksErrorMacro, ["a/b@1.2.3"], [languages_1.Language.java, languages_1.Language.python], /The configuration file "\/a\/b" is invalid: property "packs" must split packages by language/); (0, ava_1.default)("no language", parsePacksErrorMacro, ["a/b@1.2.3"], [languages_1.Language.java, languages_1.Language.python], /The configuration file "\/a\/b" is invalid: property "packs" must split packages by language/);
(0, ava_1.default)("invalid language", parsePacksErrorMacro, { [languages_1.Language.java]: ["c/d"] }, [languages_1.Language.cpp], /The configuration file "\/a\/b" is invalid: property "packs" has "java", but it is not one of the languages to analyze/);
(0, ava_1.default)("not an array", parsePacksErrorMacro, { [languages_1.Language.cpp]: "c/d" }, [languages_1.Language.cpp], /The configuration file "\/a\/b" is invalid: property "packs" must be an array of non-empty strings/); (0, ava_1.default)("not an array", parsePacksErrorMacro, { [languages_1.Language.cpp]: "c/d" }, [languages_1.Language.cpp], /The configuration file "\/a\/b" is invalid: property "packs" must be an array of non-empty strings/);
(0, ava_1.default)(invalidPackNameMacro, "c"); // all packs require at least a scope and a name (0, ava_1.default)(invalidPackNameMacro, "c"); // all packs require at least a scope and a name
(0, ava_1.default)(invalidPackNameMacro, "c-/d"); (0, ava_1.default)(invalidPackNameMacro, "c-/d");
@ -832,12 +837,17 @@ const invalidPackNameMacro = ava_1.default.macro({
* Test macro for testing the packs block and the packs input * Test macro for testing the packs block and the packs input
*/ */
function parseInputAndConfigMacro(t, packsFromConfig, packsFromInput, languages, expected) { function parseInputAndConfigMacro(t, packsFromConfig, packsFromInput, languages, expected) {
t.deepEqual(configUtils.parsePacks(packsFromConfig, packsFromInput, languages, "/a/b"), expected); t.deepEqual(configUtils.parsePacks(packsFromConfig, packsFromInput, languages, "/a/b", mockLogger), expected);
} }
parseInputAndConfigMacro.title = (providedTitle) => `Parse Packs input and config: ${providedTitle}`; parseInputAndConfigMacro.title = (providedTitle) => `Parse Packs input and config: ${providedTitle}`;
const mockLogger = {
info: (message) => {
console.log(message);
},
};
function parseInputAndConfigErrorMacro(t, packsFromConfig, packsFromInput, languages, expected) { function parseInputAndConfigErrorMacro(t, packsFromConfig, packsFromInput, languages, expected) {
t.throws(() => { t.throws(() => {
configUtils.parsePacks(packsFromConfig, packsFromInput, languages, "/a/b"); configUtils.parsePacks(packsFromConfig, packsFromInput, languages, "/a/b", mockLogger);
}, { }, {
message: expected, message: expected,
}); });

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@ import { getCachedCodeQL, setCodeQL } from "./codeql";
import * as configUtils from "./config-utils"; import * as configUtils from "./config-utils";
import { createFeatureFlags, FeatureFlag } from "./feature-flags"; import { createFeatureFlags, FeatureFlag } from "./feature-flags";
import { Language } from "./languages"; import { Language } from "./languages";
import { getRunnerLogger } from "./logging"; import { getRunnerLogger, Logger } from "./logging";
import { setupTests } from "./testing-utils"; import { setupTests } from "./testing-utils";
import * as util from "./util"; import * as util from "./util";
@ -1424,7 +1424,12 @@ const parsePacksMacro = test.macro({
expected: Partial<Record<Language, string[]>> expected: Partial<Record<Language, string[]>>
) => ) =>
t.deepEqual( t.deepEqual(
configUtils.parsePacksFromConfig(packsByLanguage, languages, "/a/b"), configUtils.parsePacksFromConfig(
packsByLanguage,
languages,
"/a/b",
mockLogger
),
expected expected
), ),
@ -1446,7 +1451,8 @@ const parsePacksErrorMacro = test.macro({
configUtils.parsePacksFromConfig( configUtils.parsePacksFromConfig(
packsByLanguage as string[] | Record<string, string[]>, packsByLanguage as string[] | Record<string, string[]>,
languages, languages,
"/a/b" "/a/b",
{} as Logger
), ),
{ {
message: expected, message: expected,
@ -1499,6 +1505,19 @@ test(
} }
); );
test(
"two packs with unused language in config",
parsePacksMacro,
{
[Language.cpp]: ["a/b", "c/d@1.2.3"],
[Language.java]: ["d/e", "f/g@1.2.3"],
},
[Language.cpp, Language.csharp],
{
[Language.cpp]: ["a/b", "c/d@1.2.3"],
}
);
test( test(
"packs with other valid names", "packs with other valid names",
parsePacksMacro, parsePacksMacro,
@ -1544,13 +1563,6 @@ test(
[Language.java, Language.python], [Language.java, Language.python],
/The configuration file "\/a\/b" is invalid: property "packs" must split packages by language/ /The configuration file "\/a\/b" is invalid: property "packs" must split packages by language/
); );
test(
"invalid language",
parsePacksErrorMacro,
{ [Language.java]: ["c/d"] },
[Language.cpp],
/The configuration file "\/a\/b" is invalid: property "packs" has "java", but it is not one of the languages to analyze/
);
test( test(
"not an array", "not an array",
parsePacksErrorMacro, parsePacksErrorMacro,
@ -1583,13 +1595,25 @@ function parseInputAndConfigMacro(
expected expected
) { ) {
t.deepEqual( t.deepEqual(
configUtils.parsePacks(packsFromConfig, packsFromInput, languages, "/a/b"), configUtils.parsePacks(
packsFromConfig,
packsFromInput,
languages,
"/a/b",
mockLogger
),
expected expected
); );
} }
parseInputAndConfigMacro.title = (providedTitle: string) => parseInputAndConfigMacro.title = (providedTitle: string) =>
`Parse Packs input and config: ${providedTitle}`; `Parse Packs input and config: ${providedTitle}`;
const mockLogger = {
info: (message: string) => {
console.log(message);
},
} as Logger;
function parseInputAndConfigErrorMacro( function parseInputAndConfigErrorMacro(
t: ExecutionContext<unknown>, t: ExecutionContext<unknown>,
packsFromConfig: string[] | Record<string, string[]>, packsFromConfig: string[] | Record<string, string[]>,
@ -1603,7 +1627,8 @@ function parseInputAndConfigErrorMacro(
packsFromConfig, packsFromConfig,
packsFromInput, packsFromInput,
languages, languages,
"/a/b" "/a/b",
mockLogger
); );
}, },
{ {

View file

@ -629,14 +629,11 @@ export function getPathsInvalid(configFile: string): string {
); );
} }
export function getPacksRequireLanguage( function getPacksRequireLanguage(lang: string, configFile: string): string {
lang: string,
configFile: string
): string {
return getConfigFilePropertyError( return getConfigFilePropertyError(
configFile, configFile,
PACKS_PROPERTY, PACKS_PROPERTY,
`has "${lang}", but it is not one of the languages to analyze` `has "${lang}", but it is not a valid language.`
); );
} }
@ -1026,7 +1023,8 @@ async function loadConfig(
parsedYAML[PACKS_PROPERTY] ?? {}, parsedYAML[PACKS_PROPERTY] ?? {},
packsInput, packsInput,
languages, languages,
configFile configFile,
logger
); );
// If queries were provided using `with` in the action configuration, // If queries were provided using `with` in the action configuration,
@ -1146,7 +1144,8 @@ const PACK_IDENTIFIER_PATTERN = (function () {
export function parsePacksFromConfig( export function parsePacksFromConfig(
packsByLanguage: string[] | Record<string, string[]>, packsByLanguage: string[] | Record<string, string[]>,
languages: Language[], languages: Language[],
configFile: string configFile: string,
logger: Logger
): Packs { ): Packs {
const packs = {}; const packs = {};
@ -1168,7 +1167,16 @@ export function parsePacksFromConfig(
throw new Error(getPacksInvalid(configFile)); throw new Error(getPacksInvalid(configFile));
} }
if (!languages.includes(lang as Language)) { if (!languages.includes(lang as Language)) {
throw new Error(getPacksRequireLanguage(lang, configFile)); // This particular language is not being analyzed in this run.
if (Language[lang as Language]) {
logger.info(
`Ignoring packs for ${lang} since this language is not being analyzed in this run.`
);
continue;
} else {
// This language is invalid, probably a misspelling
throw new Error(getPacksRequireLanguage(configFile, lang));
}
} }
packs[lang] = []; packs[lang] = [];
for (const packStr of packsArr) { for (const packStr of packsArr) {
@ -1296,13 +1304,15 @@ export function parsePacks(
rawPacksFromConfig: string[] | Record<string, string[]>, rawPacksFromConfig: string[] | Record<string, string[]>,
rawPacksInput: string | undefined, rawPacksInput: string | undefined,
languages: Language[], languages: Language[],
configFile: string configFile: string,
logger: Logger
) { ) {
const packsFromInput = parsePacksFromInput(rawPacksInput, languages); const packsFromInput = parsePacksFromInput(rawPacksInput, languages);
const packsFomConfig = parsePacksFromConfig( const packsFomConfig = parsePacksFromConfig(
rawPacksFromConfig, rawPacksFromConfig,
languages, languages,
configFile configFile,
logger
); );
if (!packsFromInput) { if (!packsFromInput) {

View file

@ -6,6 +6,9 @@ packs:
- dsp-testing/codeql-pack1@1.0.0 - dsp-testing/codeql-pack1@1.0.0
- dsp-testing/codeql-pack2 - dsp-testing/codeql-pack2
- dsp-testing/codeql-pack3:other-query.ql - dsp-testing/codeql-pack3:other-query.ql
ruby:
- dsp-testing/hucairz
- dsp-testing/i-dont-exist@1.0.0
paths-ignore: paths-ignore:
- tests - tests